Merge "Fix issue where AOD would not start" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 30d4409..874d76f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1159,7 +1159,7 @@
// into wifi-service
java_library {
name: "framework-wifi-util-lib",
- sdk_version: "core_current",
+ sdk_version: "module_current",
srcs: [
"core/java/android/content/pm/BaseParceledListSlice.java",
"core/java/android/content/pm/ParceledListSlice.java",
@@ -1175,7 +1175,6 @@
libs: [
"framework-annotations-lib",
"unsupportedappusage",
- "android_system_stubs_current",
],
visibility: ["//frameworks/base/wifi"],
}
@@ -1279,8 +1278,7 @@
aidl: {
export_include_dirs: ["telephony/java"],
},
- sdk_version: "core_current",
- libs: ["android_system_stubs_current"],
+ sdk_version: "module_current",
}
filegroup {
diff --git a/StubLibraries.bp b/StubLibraries.bp
index ccd87335..60f6174 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -95,6 +95,7 @@
api_filename: "public_api.txt",
private_api_filename: "private.txt",
removed_api_filename: "removed.txt",
+ removed_dex_api_filename: "removed-dex.txt",
arg_files: [
"core/res/AndroidManifest.xml",
],
@@ -141,6 +142,7 @@
private_api_filename: "system-private.txt",
private_dex_api_filename: "system-private-dex.txt",
removed_api_filename: "system-removed.txt",
+ removed_dex_api_filename: "system-removed-dex.txt",
arg_files: [
"core/res/AndroidManifest.xml",
],
@@ -340,44 +342,6 @@
}
/////////////////////////////////////////////////////////////////////
-// Stubs for hiddenapi processing.
-/////////////////////////////////////////////////////////////////////
-
-droidstubs {
- name: "hiddenapi-lists-docs",
- defaults: ["metalava-full-api-stubs-default"],
- arg_files: [
- "core/res/AndroidManifest.xml",
- ],
- dex_api_filename: "public-dex.txt",
- private_dex_api_filename: "private-dex.txt",
- removed_dex_api_filename: "removed-dex.txt",
- args: metalava_framework_docs_args +
- " --show-unannotated " +
- priv_apps +
- " --show-annotation android.annotation.TestApi ",
-}
-
-droidstubs {
- name: "hiddenapi-mappings",
- defaults: ["metalava-full-api-stubs-default"],
- srcs: [
- ":opt-telephony-common-srcs",
- ],
-
- arg_files: [
- "core/res/AndroidManifest.xml",
- ],
- dex_mapping_filename: "dex-mapping.txt",
- args: metalava_framework_docs_args +
- " --hide ReferencesHidden " +
- " --hide UnhiddenSystemApi " +
- " --show-unannotated " +
- priv_apps +
- " --show-annotation android.annotation.TestApi ",
-}
-
-/////////////////////////////////////////////////////////////////////
// api/*-current.txt files for use by modules in other directories
// like the CTS test
/////////////////////////////////////////////////////////////////////
diff --git a/aidl_api/libincremental_aidl/current/android/os/incremental/IncrementalFileSystemControlParcel.aidl b/aidl_api/libincremental_aidl/current/android/os/incremental/IncrementalFileSystemControlParcel.aidl
deleted file mode 100644
index d777e34..0000000
--- a/aidl_api/libincremental_aidl/current/android/os/incremental/IncrementalFileSystemControlParcel.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
-//
-// You must not make a backward incompatible changes to the AIDL files built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.os.incremental;
-/* @hide */
-parcelable IncrementalFileSystemControlParcel {
- ParcelFileDescriptor cmd;
- ParcelFileDescriptor pendingReads;
- ParcelFileDescriptor log;
-}
diff --git a/aidl_api/libincremental_manager_aidl/current/android/os/incremental/IIncrementalService.aidl b/aidl_api/libincremental_manager_aidl/current/android/os/incremental/IIncrementalService.aidl
deleted file mode 100644
index 5e1f013..0000000
--- a/aidl_api/libincremental_manager_aidl/current/android/os/incremental/IIncrementalService.aidl
+++ /dev/null
@@ -1,44 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
-//
-// You must not make a backward incompatible changes to the AIDL files built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.os.incremental;
-/* @hide */
-interface IIncrementalService {
- int openStorage(in @utf8InCpp String path);
- int createStorage(in @utf8InCpp String path, in android.content.pm.DataLoaderParamsParcel params, in android.content.pm.IDataLoaderStatusListener listener, int createMode);
- int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
- int makeBindMount(int storageId, in @utf8InCpp String sourcePath, in @utf8InCpp String targetFullPath, int bindType);
- int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
- int makeDirectory(int storageId, in @utf8InCpp String path);
- int makeDirectories(int storageId, in @utf8InCpp String path);
- int makeFile(int storageId, in @utf8InCpp String path, in android.os.incremental.IncrementalNewFileParams params);
- int makeFileFromRange(int storageId, in @utf8InCpp String targetPath, in @utf8InCpp String sourcePath, long start, long end);
- int makeLink(int sourceStorageId, in @utf8InCpp String sourcePath, int destStorageId, in @utf8InCpp String destPath);
- int unlink(int storageId, in @utf8InCpp String path);
- boolean isFileRangeLoaded(int storageId, in @utf8InCpp String path, long start, long end);
- byte[] getMetadataByPath(int storageId, in @utf8InCpp String path);
- byte[] getMetadataById(int storageId, in byte[] fileId);
- boolean startLoading(int storageId);
- void deleteStorage(int storageId);
- boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi);
- const int CREATE_MODE_TEMPORARY_BIND = 1;
- const int CREATE_MODE_PERMANENT_BIND = 2;
- const int CREATE_MODE_CREATE = 4;
- const int CREATE_MODE_OPEN_EXISTING = 8;
- const int BIND_TEMPORARY = 0;
- const int BIND_PERMANENT = 1;
-}
diff --git a/aidl_api/libincremental_manager_aidl/current/android/os/incremental/IncrementalNewFileParams.aidl b/aidl_api/libincremental_manager_aidl/current/android/os/incremental/IncrementalNewFileParams.aidl
deleted file mode 100644
index c737877..0000000
--- a/aidl_api/libincremental_manager_aidl/current/android/os/incremental/IncrementalNewFileParams.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
-//
-// You must not make a backward incompatible changes to the AIDL files built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.os.incremental;
-/* @hide */
-parcelable IncrementalNewFileParams {
- long size;
- byte[] fileId;
- byte[] metadata;
- @nullable byte[] signature;
-}
diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
index 9e46365..29721c5 100644
--- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
@@ -22,6 +22,7 @@
import android.content.pm.parsing.ParsingPackageImpl
import android.content.pm.parsing.ParsingPackageRead
import android.content.pm.parsing.ParsingPackageUtils
+import android.content.pm.parsing.result.ParseInput
import android.content.pm.parsing.result.ParseTypeImpl
import android.content.res.TypedArray
import android.perftests.utils.BenchmarkState
@@ -173,7 +174,10 @@
class ParallelParser2(cacher: PackageCacher2? = null)
: ParallelParser<ParsingPackageRead>(cacher) {
- val input = ThreadLocal.withInitial { ParseTypeImpl() }
+ val input = ThreadLocal.withInitial {
+ // For testing, just disable enforcement to avoid hooking up to compat framework
+ ParseTypeImpl(ParseInput.Callback { _, _, _ -> false })
+ }
val parser = ParsingPackageUtils(false, null, null,
object : ParsingPackageUtils.Callback {
override fun hasFeature(feature: String) = true
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 7480ec8..6f29141 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -146,7 +146,8 @@
visibility: [
"//frameworks/base", // Framework
"//frameworks/base/apex/statsd", // statsd apex
- "//frameworks/opt/net/wifi/service" // wifi service
+ "//frameworks/opt/net/wifi/service", // wifi service
+ "//packages/providers/MediaProvider", // MediaProvider apk
],
}
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index 62badb4..7fbfc43 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -467,10 +467,6 @@
synchronized (sLock) {
try {
IStatsManagerService service = getIStatsManagerServiceLocked();
- if (service == null) {
- throw new StatsUnavailableException("Failed to find statsmanager when "
- + "getting experiment IDs");
- }
return service.getRegisteredExperimentIds();
} catch (RemoteException e) {
if (DEBUG) {
diff --git a/api/test-current.txt b/api/test-current.txt
index 93cedf1..0ca8b2d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5158,3 +5158,75 @@
}
+package android.window {
+
+ public class DisplayAreaOrganizer extends android.window.WindowOrganizer {
+ ctor public DisplayAreaOrganizer();
+ method public void onDisplayAreaAppeared(@NonNull android.window.WindowContainerToken);
+ method public void onDisplayAreaVanished(@NonNull android.window.WindowContainerToken);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void registerOrganizer(int);
+ field public static final int FEATURE_ROOT = 0; // 0x0
+ field public static final int FEATURE_SYSTEM_FIRST = 0; // 0x0
+ field public static final int FEATURE_SYSTEM_LAST = 10000; // 0x2710
+ field public static final int FEATURE_TASK_CONTAINER = 1; // 0x1
+ field public static final int FEATURE_UNDEFINED = -1; // 0xffffffff
+ field public static final int FEATURE_VENDOR_FIRST = 10001; // 0x2711
+ field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2
+ }
+
+ public class TaskOrganizer extends android.window.WindowOrganizer {
+ ctor public TaskOrganizer();
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static android.app.ActivityManager.RunningTaskInfo createRootTask(int, int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static boolean deleteRootTask(@NonNull android.window.WindowContainerToken);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static android.window.WindowContainerToken getImeTarget(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getRootTasks(int, @NonNull int[]);
+ method public void onBackPressedOnTaskRoot(@NonNull android.app.ActivityManager.RunningTaskInfo);
+ method public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo);
+ method public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
+ method public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void registerOrganizer(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void unregisterOrganizer();
+ }
+
+ public final class WindowContainerToken implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.view.SurfaceControl getLeash();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.WindowContainerToken> CREATOR;
+ }
+
+ public final class WindowContainerTransaction implements android.os.Parcelable {
+ ctor public WindowContainerTransaction();
+ method public int describeContents();
+ method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
+ method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int);
+ method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
+ method @NonNull public android.window.WindowContainerTransaction setBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
+ method @NonNull public android.window.WindowContainerTransaction setBoundsChangeTransaction(@NonNull android.window.WindowContainerToken, @NonNull android.view.SurfaceControl.Transaction);
+ method @NonNull public android.window.WindowContainerTransaction setFocusable(@NonNull android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction setHidden(@NonNull android.window.WindowContainerToken, boolean);
+ method @NonNull public android.window.WindowContainerTransaction setScreenSizeDp(@NonNull android.window.WindowContainerToken, int, int);
+ method @NonNull public android.window.WindowContainerTransaction setSmallestScreenWidthDp(@NonNull android.window.WindowContainerToken, int);
+ method @NonNull public android.window.WindowContainerTransaction setWindowingMode(@NonNull android.window.WindowContainerToken, int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.WindowContainerTransaction> CREATOR;
+ }
+
+ public abstract class WindowContainerTransactionCallback {
+ ctor public WindowContainerTransactionCallback();
+ method public abstract void onTransactionReady(int, @NonNull android.view.SurfaceControl.Transaction);
+ }
+
+ public class WindowOrganizer {
+ ctor public WindowOrganizer();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void applyTransaction(@NonNull android.window.WindowContainerTransaction);
+ }
+
+}
+
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 776593d..a321460 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -78,6 +78,7 @@
"src/matchers/EventMatcherWizard.cpp",
"src/matchers/matcher_util.cpp",
"src/matchers/SimpleLogMatchingTracker.cpp",
+ "src/metadata_util.cpp",
"src/metrics/CountMetricProducer.cpp",
"src/metrics/duration_helper/MaxDurationTracker.cpp",
"src/metrics/duration_helper/OringDurationTracker.cpp",
@@ -340,6 +341,7 @@
"tests/log_event/LogEventQueue_test.cpp",
"tests/LogEntryMatcher_test.cpp",
"tests/LogEvent_test.cpp",
+ "tests/metadata_util_test.cpp",
"tests/metrics/CountMetricProducer_test.cpp",
"tests/metrics/DurationMetricProducer_test.cpp",
"tests/metrics/EventMetricProducer_test.cpp",
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 967fd32..3536e5a 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -16,6 +16,7 @@
#pragma once
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "annotations.h"
namespace android {
namespace os {
@@ -357,6 +358,56 @@
Value& operator=(const Value& that);
};
+class Annotations {
+public:
+ Annotations() {}
+
+ // This enum stores where particular annotations can be found in the
+ // bitmask. Note that these pos do not correspond to annotation ids.
+ enum {
+ NESTED_POS = 0x0,
+ PRIMARY_POS = 0x1,
+ EXCLUSIVE_POS = 0x2
+ };
+
+ inline void setNested(bool nested) { setBitmaskAtPos(NESTED_POS, nested); }
+
+ inline void setPrimaryField(bool primary) { setBitmaskAtPos(PRIMARY_POS, primary); }
+
+ inline void setExclusiveState(bool exclusive) { setBitmaskAtPos(EXCLUSIVE_POS, exclusive); }
+
+ inline void setResetState(int resetState) { mResetState = resetState; }
+
+ // Default value = false
+ inline bool isNested() const { return getValueFromBitmask(NESTED_POS); }
+
+ // Default value = false
+ inline bool isPrimaryField() const { return getValueFromBitmask(PRIMARY_POS); }
+
+ // Default value = false
+ inline bool isExclusiveState() const { return getValueFromBitmask(EXCLUSIVE_POS); }
+
+ // If a reset state is not sent in the StatsEvent, returns -1. Note that a
+ // reset satate is only sent if and only if a reset should be triggered.
+ inline int getResetState() const { return mResetState; }
+
+private:
+ inline void setBitmaskAtPos(int pos, bool value) {
+ mBooleanBitmask &= ~(1 << pos); // clear
+ mBooleanBitmask |= (value << pos); // set
+ }
+
+ inline bool getValueFromBitmask(int pos) const {
+ return (mBooleanBitmask >> pos) & 0x1;
+ }
+
+ // This is a bitmask over all annotations stored in boolean form. Because
+ // there are only 3 booleans, just one byte is required.
+ uint8_t mBooleanBitmask = 0;
+
+ int mResetState = -1;
+};
+
/**
* Represents a log item, or a dimension item (They are essentially the same).
*/
@@ -384,6 +435,7 @@
Field mField;
Value mValue;
+ Annotations mAnnotations;
};
bool HasPositionANY(const FieldMatcher& matcher);
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 4966b2e..982a63e 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -79,6 +79,7 @@
#define NS_PER_HOUR 3600 * NS_PER_SEC
#define STATS_ACTIVE_METRIC_DIR "/data/misc/stats-active-metric"
+#define STATS_METADATA_DIR "/data/misc/stats-metadata"
// Cool down period for writing data to disk to avoid overwriting files.
#define WRITE_DATA_COOL_DOWN_SEC 5
@@ -852,6 +853,110 @@
proto.flush(fd.get());
}
+void StatsLogProcessor::SaveMetadataToDisk(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs) {
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
+ // Do not write to disk if we already have in the last few seconds.
+ if (static_cast<unsigned long long> (systemElapsedTimeNs) <
+ mLastMetadataWriteNs + WRITE_DATA_COOL_DOWN_SEC * NS_PER_SEC) {
+ ALOGI("Statsd skipping writing metadata to disk. Already wrote data in last %d seconds",
+ WRITE_DATA_COOL_DOWN_SEC);
+ return;
+ }
+ mLastMetadataWriteNs = systemElapsedTimeNs;
+
+ metadata::StatsMetadataList metadataList;
+ WriteMetadataToProtoLocked(
+ currentWallClockTimeNs, systemElapsedTimeNs, &metadataList);
+
+ string file_name = StringPrintf("%s/metadata", STATS_METADATA_DIR);
+ StorageManager::deleteFile(file_name.c_str());
+
+ if (metadataList.stats_metadata_size() == 0) {
+ // Skip the write if we have nothing to write.
+ return;
+ }
+
+ std::string data;
+ metadataList.SerializeToString(&data);
+ StorageManager::writeFile(file_name.c_str(), data.c_str(), data.size());
+}
+
+void StatsLogProcessor::WriteMetadataToProto(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs,
+ metadata::StatsMetadataList* metadataList) {
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
+ WriteMetadataToProtoLocked(currentWallClockTimeNs, systemElapsedTimeNs, metadataList);
+}
+
+void StatsLogProcessor::WriteMetadataToProtoLocked(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs,
+ metadata::StatsMetadataList* metadataList) {
+ for (const auto& pair : mMetricsManagers) {
+ const sp<MetricsManager>& metricsManager = pair.second;
+ metadata::StatsMetadata* statsMetadata = metadataList->add_stats_metadata();
+ bool metadataWritten = metricsManager->writeMetadataToProto(currentWallClockTimeNs,
+ systemElapsedTimeNs, statsMetadata);
+ if (!metadataWritten) {
+ metadataList->mutable_stats_metadata()->RemoveLast();
+ }
+ }
+}
+
+void StatsLogProcessor::LoadMetadataFromDisk(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs) {
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
+ string file_name = StringPrintf("%s/metadata", STATS_METADATA_DIR);
+ int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
+ if (-1 == fd) {
+ VLOG("Attempt to read %s but failed", file_name.c_str());
+ StorageManager::deleteFile(file_name.c_str());
+ return;
+ }
+ string content;
+ if (!android::base::ReadFdToString(fd, &content)) {
+ ALOGE("Attempt to read %s but failed", file_name.c_str());
+ close(fd);
+ StorageManager::deleteFile(file_name.c_str());
+ return;
+ }
+
+ close(fd);
+
+ metadata::StatsMetadataList statsMetadataList;
+ if (!statsMetadataList.ParseFromString(content)) {
+ ALOGE("Attempt to read %s but failed; failed to metadata", file_name.c_str());
+ StorageManager::deleteFile(file_name.c_str());
+ return;
+ }
+ SetMetadataStateLocked(statsMetadataList, currentWallClockTimeNs, systemElapsedTimeNs);
+ StorageManager::deleteFile(file_name.c_str());
+}
+
+void StatsLogProcessor::SetMetadataState(const metadata::StatsMetadataList& statsMetadataList,
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs) {
+ std::lock_guard<std::mutex> lock(mMetricsMutex);
+ SetMetadataStateLocked(statsMetadataList, currentWallClockTimeNs, systemElapsedTimeNs);
+}
+
+void StatsLogProcessor::SetMetadataStateLocked(
+ const metadata::StatsMetadataList& statsMetadataList,
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs) {
+ for (const metadata::StatsMetadata& metadata : statsMetadataList.stats_metadata()) {
+ ConfigKey key(metadata.config_key().uid(), metadata.config_key().config_id());
+ auto it = mMetricsManagers.find(key);
+ if (it == mMetricsManagers.end()) {
+ ALOGE("No config found for configKey %s", key.ToString().c_str());
+ continue;
+ }
+ VLOG("Setting metadata %s", key.ToString().c_str());
+ it->second->loadMetadata(metadata, currentWallClockTimeNs, systemElapsedTimeNs);
+ }
+ VLOG("Successfully loaded %d metadata.", statsMetadataList.stats_metadata_size());
+}
+
void StatsLogProcessor::WriteActiveConfigsToProtoOutputStream(
int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 42e5676..14585c3 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -24,6 +24,7 @@
#include "external/StatsPullerManager.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h"
#include <stdio.h>
#include <unordered_map>
@@ -89,6 +90,23 @@
/* Load configs containing metrics with active activations from disk. */
void LoadActiveConfigsFromDisk();
+ /* Persist metadata for configs and metrics to disk. */
+ void SaveMetadataToDisk(int64_t currentWallClockTimeNs, int64_t systemElapsedTimeNs);
+
+ /* Writes the statsd metadata for all configs and metrics to StatsMetadataList. */
+ void WriteMetadataToProto(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs,
+ metadata::StatsMetadataList* metadataList);
+
+ /* Load stats metadata for configs and metrics from disk. */
+ void LoadMetadataFromDisk(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs);
+
+ /* Sets the metadata for all configs and metrics */
+ void SetMetadataState(const metadata::StatsMetadataList& statsMetadataList,
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs);
+
/* Sets the active status/ttl for all configs and metrics to the status in ActiveConfigList. */
void SetConfigsActiveState(const ActiveConfigList& activeConfigList, int64_t currentTimeNs);
@@ -173,8 +191,17 @@
void SetConfigsActiveStateLocked(const ActiveConfigList& activeConfigList,
int64_t currentTimeNs);
+ void SetMetadataStateLocked(const metadata::StatsMetadataList& statsMetadataList,
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs);
+
+ void WriteMetadataToProtoLocked(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs,
+ metadata::StatsMetadataList* metadataList);
+
void WriteDataToDiskLocked(const DumpReportReason dumpReportReason,
const DumpLatency dumpLatency);
+
void WriteDataToDiskLocked(const ConfigKey& key, const int64_t timestampNs,
const DumpReportReason dumpReportReason,
const DumpLatency dumpLatency);
@@ -241,6 +268,9 @@
// Last time we wrote active metrics to disk.
int64_t mLastActiveMetricsWriteNs = 0;
+ //Last time we wrote metadata to disk.
+ int64_t mLastMetadataWriteNs = 0;
+
#ifdef VERY_VERBOSE_PRINTING
bool mPrintAllLogs = false;
#endif
@@ -278,6 +308,9 @@
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk_no_data_written);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_load_refractory_from_disk);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 98879a0..9169eb17 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1022,6 +1022,7 @@
VLOG("StatsService::informDeviceShutdown");
mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN, FAST);
mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs());
+ mProcessor->SaveMetadataToDisk(getWallClockNs(), getElapsedRealtimeNs());
return Status::ok();
}
@@ -1056,6 +1057,7 @@
void StatsService::Startup() {
mConfigManager->Startup();
mProcessor->LoadActiveConfigsFromDisk();
+ mProcessor->LoadMetadataFromDisk(getWallClockNs(), getElapsedRealtimeNs());
}
void StatsService::Terminate() {
@@ -1063,6 +1065,7 @@
if (mProcessor != nullptr) {
mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST);
mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs());
+ mProcessor->SaveMetadataToDisk(getWallClockNs(), getElapsedRealtimeNs());
}
}
@@ -1295,20 +1298,23 @@
if (mProcessor != nullptr) {
ALOGW("Reset statsd upon system server restarts.");
int64_t systemServerRestartNs = getElapsedRealtimeNs();
- ProtoOutputStream proto;
+ ProtoOutputStream activeConfigsProto;
mProcessor->WriteActiveConfigsToProtoOutputStream(systemServerRestartNs,
- STATSCOMPANION_DIED, &proto);
-
+ STATSCOMPANION_DIED, &activeConfigsProto);
+ metadata::StatsMetadataList metadataList;
+ mProcessor->WriteMetadataToProto(getWallClockNs(),
+ systemServerRestartNs, &metadataList);
mProcessor->WriteDataToDisk(STATSCOMPANION_DIED, FAST);
mProcessor->resetConfigs();
std::string serializedActiveConfigs;
- if (proto.serializeToString(&serializedActiveConfigs)) {
+ if (activeConfigsProto.serializeToString(&serializedActiveConfigs)) {
ActiveConfigList activeConfigs;
if (activeConfigs.ParseFromString(serializedActiveConfigs)) {
mProcessor->SetConfigsActiveState(activeConfigs, systemServerRestartNs);
}
}
+ mProcessor->SetMetadataState(metadataList, getWallClockNs(), systemServerRestartNs);
}
mAnomalyAlarmMonitor->setStatsCompanionService(nullptr);
mPeriodicAlarmMonitor->setStatsCompanionService(nullptr);
diff --git a/cmds/statsd/src/annotations.h b/cmds/statsd/src/annotations.h
new file mode 100644
index 0000000..1e9390e
--- /dev/null
+++ b/cmds/statsd/src/annotations.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+namespace android {
+namespace os {
+namespace statsd {
+
+const uint8_t ANNOTATION_ID_IS_UID = 1;
+const uint8_t ANNOTATION_ID_TRUNCATE_TIMESTAMP = 2;
+const uint8_t ANNOTATION_ID_STATE_OPTION = 3;
+const uint8_t ANNOTATION_ID_RESET_STATE = 5;
+const uint8_t ANNOTATION_ID_STATE_NESTED = 6;
+
+const int32_t STATE_OPTION_PRIMARY_FIELD = 1;
+const int32_t STATE_OPTION_EXCLUSIVE_STATE = 2;
+const int32_t STATE_OPTION_PRIMARY_FIELD_FIRST_UID = 3;
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index a21abbf..619752c 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -18,9 +18,11 @@
#include "Log.h"
#include "AnomalyTracker.h"
-#include "subscriber_util.h"
#include "external/Perfetto.h"
#include "guardrail/StatsdStats.h"
+#include "metadata_util.h"
+#include "stats_log_util.h"
+#include "subscriber_util.h"
#include "subscriber/IncidentdReporter.h"
#include "subscriber/SubscriberReporter.h"
@@ -262,6 +264,58 @@
triggerSubscribers(mAlert.id(), metric_id, key, metricValue, mConfigKey, mSubscriptions);
}
+bool AnomalyTracker::writeAlertMetadataToProto(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs,
+ metadata::AlertMetadata* alertMetadata) {
+ bool metadataWritten = false;
+
+ if (mRefractoryPeriodEndsSec.empty()) {
+ return false;
+ }
+
+ for (const auto& it: mRefractoryPeriodEndsSec) {
+ // Do not write the timestamp to disk if it has already expired
+ if (it.second < systemElapsedTimeNs / NS_PER_SEC) {
+ continue;
+ }
+
+ metadataWritten = true;
+ if (alertMetadata->alert_dim_keyed_data_size() == 0) {
+ alertMetadata->set_alert_id(mAlert.id());
+ }
+
+ metadata::AlertDimensionKeyedData* keyedData = alertMetadata->add_alert_dim_keyed_data();
+ // We convert and write the refractory_end_sec to wall clock time because we do not know
+ // when statsd will start again.
+ int32_t refractoryEndWallClockSec = (int32_t) ((currentWallClockTimeNs / NS_PER_SEC) +
+ (it.second - systemElapsedTimeNs / NS_PER_SEC));
+
+ keyedData->set_last_refractory_ends_sec(refractoryEndWallClockSec);
+ writeMetricDimensionKeyToMetadataDimensionKey(
+ it.first, keyedData->mutable_dimension_key());
+ }
+
+ return metadataWritten;
+}
+
+void AnomalyTracker::loadAlertMetadata(
+ const metadata::AlertMetadata& alertMetadata,
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs) {
+ for (const metadata::AlertDimensionKeyedData& keyedData :
+ alertMetadata.alert_dim_keyed_data()) {
+ if ((uint64_t) keyedData.last_refractory_ends_sec() < currentWallClockTimeNs / NS_PER_SEC) {
+ // Do not update the timestamp if it has already expired.
+ continue;
+ }
+ MetricDimensionKey metricKey = loadMetricDimensionKeyFromProto(
+ keyedData.dimension_key());
+ int32_t refractoryPeriodEndsSec = (int32_t) keyedData.last_refractory_ends_sec() -
+ currentWallClockTimeNs / NS_PER_SEC + systemElapsedTimeNs / NS_PER_SEC;
+ mRefractoryPeriodEndsSec[metricKey] = refractoryPeriodEndsSec;
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 794ee98..bf36a3b 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -24,6 +24,7 @@
#include "AlarmMonitor.h"
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
+#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h" // AlertMetadata
#include "stats_util.h" // HashableDimensionKey and DimToValMap
namespace android {
@@ -112,6 +113,17 @@
return; // The base AnomalyTracker class doesn't have alarms.
}
+ // Writes metadata of the alert (refractory_period_end_sec) to AlertMetadata.
+ // Returns true if at least one element is written to alertMetadata.
+ bool writeAlertMetadataToProto(
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs, metadata::AlertMetadata* alertMetadata);
+
+ void loadAlertMetadata(
+ const metadata::AlertMetadata& alertMetadata,
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs);
+
protected:
// For testing only.
// Returns the alarm timestamp in seconds for the query dimension if it exists. Otherwise
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 6a4338f..57d4d78 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5810,7 +5810,7 @@
*/
message PackageNotificationPreferences {
// Uid under which the package is installed.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// Notification importance, which specifies when and how a notification is displayed.
// Specified under core/java/android/app/NotificationManager.java.
optional int32 importance = 2;
@@ -5827,7 +5827,7 @@
*/
message PackageNotificationChannelPreferences {
// Uid under which the package is installed.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// Channel's ID. Should always be available.
optional string channel_id = 2;
// Channel's name. Should always be available.
@@ -5850,7 +5850,7 @@
*/
message PackageNotificationChannelGroupPreferences {
// Uid under which the package is installed.
- optional int32 uid = 1;
+ optional int32 uid = 1 [(is_uid) = true];
// Channel Group's ID. Should always be available.
optional string group_id = 2;
// Channel Group's name. Should always be available.
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 3b3d0b6..a6ae389 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -17,6 +17,7 @@
#define DEBUG false // STOPSHIP if true
#include "logd/LogEvent.h"
+#include "annotations.h"
#include "stats_log_util.h"
#include "statslog_statsd.h"
@@ -447,6 +448,7 @@
void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
uint8_t numAnnotations) {
+ int firstUidInChainIndex = mValues.size();
int32_t numNodes = readNextValue<uint8_t>();
for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
last[1] = (pos[1] == numNodes);
@@ -461,26 +463,103 @@
parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
}
- parseAnnotations(numAnnotations);
+ parseAnnotations(numAnnotations, firstUidInChainIndex);
pos[1] = pos[2] = 1;
last[1] = last[2] = false;
}
-// TODO(b/151109630): store annotation information within LogEvent
-void LogEvent::parseAnnotations(uint8_t numAnnotations) {
+void LogEvent::parseIsUidAnnotation(uint8_t annotationType) {
+ if (mValues.empty() || annotationType != BOOL_TYPE) {
+ mValid = false;
+ return;
+ }
+
+ bool isUid = readNextValue<uint8_t>();
+ if (isUid) mUidFieldIndex = mValues.size() - 1;
+}
+
+void LogEvent::parseTruncateTimestampAnnotation(uint8_t annotationType) {
+ if (!mValues.empty() || annotationType != BOOL_TYPE) {
+ mValid = false;
+ return;
+ }
+
+ mTruncateTimestamp = readNextValue<uint8_t>();
+}
+
+void LogEvent::parseStateOptionAnnotation(uint8_t annotationType, int firstUidInChainIndex) {
+ if (mValues.empty() || annotationType != INT32_TYPE) {
+ mValid = false;
+ return;
+ }
+
+ int32_t stateOption = readNextValue<int32_t>();
+ switch (stateOption) {
+ case STATE_OPTION_EXCLUSIVE_STATE:
+ mValues[mValues.size() - 1].mAnnotations.setExclusiveState(true);
+ break;
+ case STATE_OPTION_PRIMARY_FIELD:
+ mValues[mValues.size() - 1].mAnnotations.setPrimaryField(true);
+ break;
+ case STATE_OPTION_PRIMARY_FIELD_FIRST_UID:
+ if (firstUidInChainIndex == -1) {
+ mValid = false;
+ } else {
+ mValues[firstUidInChainIndex].mAnnotations.setPrimaryField(true);
+ }
+ break;
+ default:
+ mValid = false;
+ }
+}
+
+void LogEvent::parseResetStateAnnotation(uint8_t annotationType) {
+ if (mValues.empty() || annotationType != INT32_TYPE) {
+ mValid = false;
+ return;
+ }
+
+ int32_t resetState = readNextValue<int32_t>();
+ mValues[mValues.size() - 1].mAnnotations.setResetState(resetState);
+}
+
+void LogEvent::parseStateNestedAnnotation(uint8_t annotationType) {
+ if (mValues.empty() || annotationType != BOOL_TYPE) {
+ mValid = false;
+ return;
+ }
+
+ bool nested = readNextValue<uint8_t>();
+ mValues[mValues.size() - 1].mAnnotations.setNested(nested);
+}
+
+// firstUidInChainIndex is a default parameter that is only needed when parsing
+// annotations for attribution chains.
+void LogEvent::parseAnnotations(uint8_t numAnnotations, int firstUidInChainIndex) {
for (uint8_t i = 0; i < numAnnotations; i++) {
- /*uint8_t annotationId = */ readNextValue<uint8_t>();
+ uint8_t annotationId = readNextValue<uint8_t>();
uint8_t annotationType = readNextValue<uint8_t>();
- switch (annotationType) {
- case BOOL_TYPE:
- /*bool annotationValue = */ readNextValue<uint8_t>();
+
+ switch (annotationId) {
+ case ANNOTATION_ID_IS_UID:
+ parseIsUidAnnotation(annotationType);
break;
- case INT32_TYPE:
- /*int32_t annotationValue =*/ readNextValue<int32_t>();
+ case ANNOTATION_ID_TRUNCATE_TIMESTAMP:
+ parseTruncateTimestampAnnotation(annotationType);
+ break;
+ case ANNOTATION_ID_STATE_OPTION:
+ parseStateOptionAnnotation(annotationType, firstUidInChainIndex);
+ break;
+ case ANNOTATION_ID_RESET_STATE:
+ parseResetStateAnnotation(annotationType);
+ break;
+ case ANNOTATION_ID_STATE_NESTED:
+ parseStateNestedAnnotation(annotationType);
break;
default:
mValid = false;
+ return;
}
}
}
@@ -509,8 +588,8 @@
typeInfo = readNextValue<uint8_t>();
if (getTypeId(typeInfo) != INT32_TYPE) mValid = false;
mTagId = readNextValue<int32_t>();
- parseAnnotations(getNumAnnotations(typeInfo)); // atom-level annotations
numElements--;
+ parseAnnotations(getNumAnnotations(typeInfo)); // atom-level annotations
for (pos[0] = 1; pos[0] <= numElements && mValid; pos[0]++) {
@@ -544,6 +623,7 @@
break;
case ATTRIBUTION_CHAIN_TYPE:
parseAttributionChain(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
+ if (mAttributionChainIndex == -1) mAttributionChainIndex = pos[0];
break;
default:
mValid = false;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 6537f13..0a89be4 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -206,6 +206,32 @@
return &mValues;
}
+ // Default value = false
+ inline bool shouldTruncateTimestamp() {
+ return mTruncateTimestamp;
+ }
+
+ // Returns the index of the uid field within the FieldValues vector if the
+ // uid exists. If there is no uid field, returns -1.
+ //
+ // If the index within the atom definition is desired, do the following:
+ // int vectorIndex = LogEvent.getUidFieldIndex();
+ // if (vectorIndex != -1) {
+ // FieldValue& v = LogEvent.getValues()[vectorIndex];
+ // int atomIndex = v.mField.getPosAtDepth(0);
+ // }
+ // Note that atomIndex is 1-indexed.
+ inline int getUidFieldIndex() {
+ return mUidFieldIndex;
+ }
+
+ // Returns the index of (the first) attribution chain within the atom
+ // definition. Note that the value is 1-indexed. If there is no attribution
+ // chain, returns -1.
+ inline int getAttributionChainIndex() {
+ return mAttributionChainIndex;
+ }
+
inline LogEvent makeCopy() {
return LogEvent(*this);
}
@@ -240,7 +266,13 @@
void parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
void parseAttributionChain(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
- void parseAnnotations(uint8_t numAnnotations);
+
+ void parseAnnotations(uint8_t numAnnotations, int firstUidInChainIndex = -1);
+ void parseIsUidAnnotation(uint8_t annotationType);
+ void parseTruncateTimestampAnnotation(uint8_t annotationType);
+ void parseStateOptionAnnotation(uint8_t annotationType, int firstUidInChainIndex);
+ void parseResetStateAnnotation(uint8_t annotationType);
+ void parseStateNestedAnnotation(uint8_t annotationType);
/**
* The below three variables are only valid during the execution of
@@ -322,6 +354,11 @@
// The pid of the logging client (defaults to -1).
int32_t mLogPid = -1;
+
+ // Annotations
+ bool mTruncateTimestamp = false;
+ int mUidFieldIndex = -1;
+ int mAttributionChainIndex = -1;
};
void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
diff --git a/cmds/statsd/src/metadata_util.cpp b/cmds/statsd/src/metadata_util.cpp
new file mode 100644
index 0000000..27ee59b
--- /dev/null
+++ b/cmds/statsd/src/metadata_util.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 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 "FieldValue.h"
+#include "metadata_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using google::protobuf::RepeatedPtrField;
+
+void writeValueToProto(metadata::FieldValue* metadataFieldValue, const Value& value) {
+ std::string storage_value;
+ switch (value.getType()) {
+ case INT:
+ metadataFieldValue->set_value_int(value.int_value);
+ break;
+ case LONG:
+ metadataFieldValue->set_value_long(value.long_value);
+ break;
+ case FLOAT:
+ metadataFieldValue->set_value_float(value.float_value);
+ break;
+ case DOUBLE:
+ metadataFieldValue->set_value_double(value.double_value);
+ break;
+ case STRING:
+ metadataFieldValue->set_value_str(value.str_value.c_str());
+ break;
+ case STORAGE: // byte array
+ storage_value = ((char*) value.storage_value.data());
+ metadataFieldValue->set_value_storage(storage_value);
+ break;
+ default:
+ break;
+ }
+}
+
+void writeMetricDimensionKeyToMetadataDimensionKey(
+ const MetricDimensionKey& metricKey,
+ metadata::MetricDimensionKey* metadataMetricKey) {
+ for (const FieldValue& fieldValue : metricKey.getDimensionKeyInWhat().getValues()) {
+ metadata::FieldValue* metadataFieldValue = metadataMetricKey->add_dimension_key_in_what();
+ metadata::Field* metadataField = metadataFieldValue->mutable_field();
+ metadataField->set_tag(fieldValue.mField.getTag());
+ metadataField->set_field(fieldValue.mField.getField());
+ writeValueToProto(metadataFieldValue, fieldValue.mValue);
+ }
+
+ for (const FieldValue& fieldValue : metricKey.getStateValuesKey().getValues()) {
+ metadata::FieldValue* metadataFieldValue = metadataMetricKey->add_state_values_key();
+ metadata::Field* metadataField = metadataFieldValue->mutable_field();
+ metadataField->set_tag(fieldValue.mField.getTag());
+ metadataField->set_field(fieldValue.mField.getField());
+ writeValueToProto(metadataFieldValue, fieldValue.mValue);
+ }
+}
+
+void writeFieldValuesFromMetadata(
+ const RepeatedPtrField<metadata::FieldValue>& repeatedFieldValueList,
+ std::vector<FieldValue>* fieldValues) {
+ for (const metadata::FieldValue& metadataFieldValue : repeatedFieldValueList) {
+ Field field(metadataFieldValue.field().tag(), metadataFieldValue.field().field());
+ Value value;
+ switch (metadataFieldValue.value_case()) {
+ case metadata::FieldValue::ValueCase::kValueInt:
+ value = Value(metadataFieldValue.value_int());
+ break;
+ case metadata::FieldValue::ValueCase::kValueLong:
+ value = Value(metadataFieldValue.value_long());
+ break;
+ case metadata::FieldValue::ValueCase::kValueFloat:
+ value = Value(metadataFieldValue.value_float());
+ break;
+ case metadata::FieldValue::ValueCase::kValueDouble:
+ value = Value(metadataFieldValue.value_double());
+ break;
+ case metadata::FieldValue::ValueCase::kValueStr:
+ value = Value(metadataFieldValue.value_str());
+ break;
+ case metadata::FieldValue::ValueCase::kValueStorage:
+ value = Value(metadataFieldValue.value_storage());
+ break;
+ default:
+ break;
+ }
+ FieldValue fieldValue(field, value);
+ fieldValues->emplace_back(field, value);
+ }
+}
+
+MetricDimensionKey loadMetricDimensionKeyFromProto(
+ const metadata::MetricDimensionKey& metricDimensionKey) {
+ std::vector<FieldValue> dimKeyInWhatFieldValues;
+ writeFieldValuesFromMetadata(metricDimensionKey.dimension_key_in_what(),
+ &dimKeyInWhatFieldValues);
+ std::vector<FieldValue> stateValuesFieldValues;
+ writeFieldValuesFromMetadata(metricDimensionKey.state_values_key(), &stateValuesFieldValues);
+
+ HashableDimensionKey dimKeyInWhat(dimKeyInWhatFieldValues);
+ HashableDimensionKey stateValues(stateValuesFieldValues);
+ MetricDimensionKey metricKey(dimKeyInWhat, stateValues);
+ return metricKey;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metadata_util.h b/cmds/statsd/src/metadata_util.h
new file mode 100644
index 0000000..84a39ff
--- /dev/null
+++ b/cmds/statsd/src/metadata_util.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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 "HashableDimensionKey.h"
+
+#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h" // AlertMetadata
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void writeMetricDimensionKeyToMetadataDimensionKey(const MetricDimensionKey& metricKey,
+ metadata::MetricDimensionKey* metadataMetricKey);
+
+MetricDimensionKey loadMetricDimensionKeyFromProto(
+ const metadata::MetricDimensionKey& metricDimensionKey);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 8ed0cbc..d832ed8 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -642,8 +642,40 @@
}
}
+bool MetricsManager::writeMetadataToProto(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs,
+ metadata::StatsMetadata* statsMetadata) {
+ bool metadataWritten = false;
+ metadata::ConfigKey* configKey = statsMetadata->mutable_config_key();
+ configKey->set_config_id(mConfigKey.GetId());
+ configKey->set_uid(mConfigKey.GetUid());
+ for (const auto& anomalyTracker : mAllAnomalyTrackers) {
+ metadata::AlertMetadata* alertMetadata = statsMetadata->add_alert_metadata();
+ bool alertWritten = anomalyTracker->writeAlertMetadataToProto(currentWallClockTimeNs,
+ systemElapsedTimeNs, alertMetadata);
+ if (!alertWritten) {
+ statsMetadata->mutable_alert_metadata()->RemoveLast();
+ }
+ metadataWritten |= alertWritten;
+ }
+ return metadataWritten;
+}
-
+void MetricsManager::loadMetadata(const metadata::StatsMetadata& metadata,
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs) {
+ for (const metadata::AlertMetadata& alertMetadata : metadata.alert_metadata()) {
+ int64_t alertId = alertMetadata.alert_id();
+ auto it = mAlertTrackerMap.find(alertId);
+ if (it == mAlertTrackerMap.end()) {
+ ALOGE("No anomalyTracker found for alertId %lld", (long long) alertId);
+ continue;
+ }
+ mAllAnomalyTrackers[it->second]->loadAlertMetadata(alertMetadata,
+ currentWallClockTimeNs,
+ systemElapsedTimeNs);
+ }
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 291f97b..3fb9166 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -23,6 +23,7 @@
#include "config/ConfigKey.h"
#include "external/StatsPullerManager.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h"
#include "logd/LogEvent.h"
#include "matchers/LogMatchingTracker.h"
#include "metrics/MetricProducer.h"
@@ -143,6 +144,14 @@
void writeActiveConfigToProtoOutputStream(
int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
+ // Returns true if at least one piece of metadata is written.
+ bool writeMetadataToProto(int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs,
+ metadata::StatsMetadata* statsMetadata);
+
+ void loadMetadata(const metadata::StatsMetadata& metadata,
+ int64_t currentWallClockTimeNs,
+ int64_t systemElapsedTimeNs);
private:
// For test only.
inline int64_t getTtlEndNs() const { return mTtlEndNs; }
@@ -285,6 +294,9 @@
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk_no_data_written);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_load_refractory_from_disk);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
diff --git a/cmds/statsd/src/statsd_metadata.proto b/cmds/statsd/src/statsd_metadata.proto
index e00fe336..200b392 100644
--- a/cmds/statsd/src/statsd_metadata.proto
+++ b/cmds/statsd/src/statsd_metadata.proto
@@ -45,11 +45,15 @@
repeated FieldValue state_values_key = 2;
}
+message AlertDimensionKeyedData {
+ // The earliest time the alert can be fired again in wall clock time.
+ optional int32 last_refractory_ends_sec = 1;
+ optional MetricDimensionKey dimension_key = 2;
+}
+
message AlertMetadata {
optional int64 alert_id = 1;
- // The earliest time the alert can be fired again in wall clock time.
- optional int32 last_refractory_ends_sec = 2;
- optional MetricDimensionKey dimension_key = 3;
+ repeated AlertDimensionKeyedData alert_dim_keyed_data = 2;
}
// All metadata for a config in statsd
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 7458cbf..41e21e4 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "src/logd/LogEvent.h"
#include <gtest/gtest.h>
-#include <log/log_event_list.h>
+
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include "frameworks/base/core/proto/android/stats/launcher/launcher.pb.h"
-#include <stats_event.h>
+#include "log/log_event_list.h"
+#include "src/logd/LogEvent.h"
+#include "stats_event.h"
#ifdef __ANDROID__
@@ -243,6 +244,117 @@
AStatsEvent_release(event);
}
+void createIntWithBoolAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
+ bool annotationValue) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
+ AStatsEvent_writeInt32(statsEvent, 10);
+ AStatsEvent_addBoolAnnotation(statsEvent, annotationId, annotationValue);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ EXPECT_TRUE(logEvent->parseBuffer(buf, size));
+
+ AStatsEvent_release(statsEvent);
+}
+
+TEST(LogEventTest, TestAnnotationIdIsUid) {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_IS_UID, true);
+
+ const vector<FieldValue>& values = event.getValues();
+ EXPECT_EQ(values.size(), 1);
+ EXPECT_EQ(event.getUidFieldIndex(), 0);
+}
+
+TEST(LogEventTest, TestAnnotationIdStateNested) {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_STATE_NESTED, true);
+
+ const vector<FieldValue>& values = event.getValues();
+ EXPECT_EQ(values.size(), 1);
+ EXPECT_TRUE(values[0].mAnnotations.isNested());
+}
+
+void createIntWithIntAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
+ int annotationValue) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
+ AStatsEvent_writeInt32(statsEvent, 10);
+ AStatsEvent_addInt32Annotation(statsEvent, annotationId, annotationValue);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ EXPECT_TRUE(logEvent->parseBuffer(buf, size));
+
+ AStatsEvent_release(statsEvent);
+}
+
+TEST(LogEventTest, TestPrimaryFieldAnnotation) {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_STATE_OPTION,
+ STATE_OPTION_PRIMARY_FIELD);
+
+ const vector<FieldValue>& values = event.getValues();
+ EXPECT_EQ(values.size(), 1);
+ EXPECT_TRUE(values[0].mAnnotations.isPrimaryField());
+}
+
+TEST(LogEventTest, TestExclusiveStateAnnotation) {
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_STATE_OPTION,
+ STATE_OPTION_EXCLUSIVE_STATE);
+
+ const vector<FieldValue>& values = event.getValues();
+ EXPECT_EQ(values.size(), 1);
+ EXPECT_TRUE(values[0].mAnnotations.isExclusiveState());
+}
+
+TEST(LogEventTest, TestPrimaryFieldFirstUidAnnotation) {
+ // Event has 10 ints and then an attribution chain
+ int numInts = 10;
+ int firstUidInChainIndex = numInts;
+ string tag1 = "tag1";
+ string tag2 = "tag2";
+ uint32_t uids[] = {1001, 1002};
+ const char* tags[] = {tag1.c_str(), tag2.c_str()};
+
+ // Construct AStatsEvent
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, 100);
+ for (int i = 0; i < numInts; i++) {
+ AStatsEvent_writeInt32(statsEvent, 10);
+ }
+ AStatsEvent_writeAttributionChain(statsEvent, uids, tags, 2);
+ AStatsEvent_addInt32Annotation(statsEvent, ANNOTATION_ID_STATE_OPTION,
+ STATE_OPTION_PRIMARY_FIELD_FIRST_UID);
+ AStatsEvent_build(statsEvent);
+
+ // Construct LogEvent
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ LogEvent logEvent(/*uid=*/0, /*pid=*/0);
+ EXPECT_TRUE(logEvent.parseBuffer(buf, size));
+ AStatsEvent_release(statsEvent);
+
+ // Check annotation
+ const vector<FieldValue>& values = logEvent.getValues();
+ EXPECT_EQ(values.size(), numInts + 4);
+ EXPECT_TRUE(values[firstUidInChainIndex].mAnnotations.isPrimaryField());
+}
+
+TEST(LogEventTest, TestResetStateAnnotation) {
+ int32_t resetState = 10;
+ LogEvent event(/*uid=*/0, /*pid=*/0);
+ createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_RESET_STATE, resetState);
+
+ const vector<FieldValue>& values = event.getValues();
+ EXPECT_EQ(values.size(), 1);
+ EXPECT_EQ(values[0].mAnnotations.getResetState(), resetState);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
index 9c6965d..c2d7043 100644
--- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
+#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h"
#include "src/StatsLogProcessor.h"
#include "src/stats_log_util.h"
#include "tests/statsd_test_util.h"
@@ -28,7 +29,7 @@
namespace {
-StatsdConfig CreateStatsdConfig(int num_buckets, int threshold) {
+StatsdConfig CreateStatsdConfig(int num_buckets, int threshold, int refractory_period_sec) {
StatsdConfig config;
config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
@@ -46,7 +47,7 @@
alert->set_id(StringToId("alert"));
alert->set_metric_id(123456);
alert->set_num_buckets(num_buckets);
- alert->set_refractory_period_secs(10);
+ alert->set_refractory_period_secs(refractory_period_sec);
alert->set_trigger_if_sum_gt(threshold);
return config;
}
@@ -56,9 +57,9 @@
TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
const int num_buckets = 1;
const int threshold = 3;
- auto config = CreateStatsdConfig(num_buckets, threshold);
+ const int refractory_period_sec = 10;
+ auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
const uint64_t alert_id = config.alert(0).id();
- const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
@@ -173,9 +174,9 @@
TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
const int num_buckets = 3;
const int threshold = 3;
- auto config = CreateStatsdConfig(num_buckets, threshold);
+ const int refractory_period_sec = 10;
+ auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
const uint64_t alert_id = config.alert(0).id();
- const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
@@ -240,6 +241,146 @@
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
}
+TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk_no_data_written) {
+ const int num_buckets = 1;
+ const int threshold = 0;
+ const int refractory_period_sec = 86400 * 365; // 1 year
+ auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
+ const int64_t alert_id = config.alert(0).id();
+
+ int64_t bucketStartTimeNs = 10000000000;
+
+ int configUid = 2000;
+ int64_t configId = 1000;
+ ConfigKey cfgKey(configUid, configId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ metadata::StatsMetadataList result;
+ int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
+ int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
+ processor->WriteMetadataToProto(mockWallClockNs, mockElapsedTimeNs, &result);
+
+ EXPECT_EQ(result.stats_metadata_size(), 0);
+}
+
+TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk) {
+ const int num_buckets = 1;
+ const int threshold = 0;
+ const int refractory_period_sec = 86400 * 365; // 1 year
+ auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
+ const int64_t alert_id = config.alert(0).id();
+
+ int64_t bucketStartTimeNs = 10000000000;
+
+ int configUid = 2000;
+ int64_t configId = 1000;
+ ConfigKey cfgKey(configUid, configId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ std::vector<int> attributionUids1 = {111};
+ std::vector<string> attributionTags1 = {"App1"};
+ std::vector<int> attributionUids2 = {111, 222};
+ std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
+
+ FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)111));
+ HashableDimensionKey whatKey1({fieldValue1});
+ MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 2) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ metadata::StatsMetadataList result;
+ int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
+ int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
+ processor->WriteMetadataToProto(mockWallClockNs, mockElapsedTimeNs, &result);
+
+ metadata::StatsMetadata statsMetadata = result.stats_metadata(0);
+ EXPECT_EQ(result.stats_metadata_size(), 1);
+ EXPECT_EQ(statsMetadata.config_key().config_id(), configId);
+ EXPECT_EQ(statsMetadata.config_key().uid(), configUid);
+
+ metadata::AlertMetadata alertMetadata = statsMetadata.alert_metadata(0);
+ EXPECT_EQ(statsMetadata.alert_metadata_size(), 1);
+ EXPECT_EQ(alertMetadata.alert_id(), alert_id);
+ metadata::AlertDimensionKeyedData keyedData = alertMetadata.alert_dim_keyed_data(0);
+ EXPECT_EQ(alertMetadata.alert_dim_keyed_data_size(), 1);
+ EXPECT_EQ(keyedData.last_refractory_ends_sec(),
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1) -
+ mockElapsedTimeNs / NS_PER_SEC +
+ mockWallClockNs / NS_PER_SEC);
+
+ metadata::MetricDimensionKey metadataDimKey = keyedData.dimension_key();
+ metadata::FieldValue dimKeyInWhat = metadataDimKey.dimension_key_in_what(0);
+ EXPECT_EQ(dimKeyInWhat.field().tag(), fieldValue1.mField.getTag());
+ EXPECT_EQ(dimKeyInWhat.field().field(), fieldValue1.mField.getField());
+ EXPECT_EQ(dimKeyInWhat.value_int(), fieldValue1.mValue.int_value);
+}
+
+TEST(AnomalyDetectionE2eTest, TestCountMetric_load_refractory_from_disk) {
+ const int num_buckets = 1;
+ const int threshold = 0;
+ const int refractory_period_sec = 86400 * 365; // 1 year
+ auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
+ const int64_t alert_id = config.alert(0).id();
+
+ int64_t bucketStartTimeNs = 10000000000;
+
+ int configUid = 2000;
+ int64_t configId = 1000;
+ ConfigKey cfgKey(configUid, configId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ std::vector<int> attributionUids1 = {111};
+ std::vector<string> attributionTags1 = {"App1"};
+ std::vector<int> attributionUids2 = {111, 222};
+ std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
+
+ FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)111));
+ HashableDimensionKey whatKey1({fieldValue1});
+ MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 2) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
+ int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
+ processor->SaveMetadataToDisk(mockWallClockNs, mockElapsedTimeNs);
+
+ auto processor2 = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ int64_t mockElapsedTimeSinceBoot = 10 * NS_PER_SEC;
+ processor2->LoadMetadataFromDisk(mockWallClockNs, mockElapsedTimeSinceBoot);
+
+ sp<AnomalyTracker> anomalyTracker2 =
+ processor2->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+ EXPECT_EQ(anomalyTracker2->getRefractoryPeriodEndsSec(dimensionKey1) -
+ mockElapsedTimeSinceBoot / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1) -
+ mockElapsedTimeNs / NS_PER_SEC);
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/metadata_util_test.cpp b/cmds/statsd/tests/metadata_util_test.cpp
new file mode 100644
index 0000000..7707890
--- /dev/null
+++ b/cmds/statsd/tests/metadata_util_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 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 <gtest/gtest.h>
+
+#include "metadata_util.h"
+#include "tests/statsd_test_util.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(MetadataUtilTest, TestWriteAndReadMetricDimensionKey) {
+ HashableDimensionKey dim;
+ HashableDimensionKey dim2;
+ int pos1[] = {1, 1, 1};
+ int pos2[] = {1, 1, 2};
+ int pos3[] = {1, 1, 3};
+ int pos4[] = {2, 0, 0};
+ Field field1(10, pos1, 2);
+ Field field2(10, pos2, 2);
+ Field field3(10, pos3, 2);
+ Field field4(10, pos4, 0);
+
+ Value value1((int32_t)10025);
+ Value value2("tag");
+ Value value3((int32_t)987654);
+ Value value4((int32_t)99999);
+
+ dim.addValue(FieldValue(field1, value1));
+ dim.addValue(FieldValue(field2, value2));
+ dim.addValue(FieldValue(field3, value3));
+ dim.addValue(FieldValue(field4, value4));
+
+ dim2.addValue(FieldValue(field1, value1));
+ dim2.addValue(FieldValue(field2, value2));
+
+ MetricDimensionKey dimKey(dim, dim2);
+
+ metadata::MetricDimensionKey metadataDimKey;
+ writeMetricDimensionKeyToMetadataDimensionKey(dimKey, &metadataDimKey);
+
+ MetricDimensionKey loadedDimKey = loadMetricDimensionKeyFromProto(metadataDimKey);
+
+ ASSERT_EQ(loadedDimKey, dimKey);
+ ASSERT_EQ(std::hash<MetricDimensionKey>{}(loadedDimKey),
+ std::hash<MetricDimensionKey>{}(dimKey));
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 556f841..2531c89 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -73,7 +73,7 @@
import android.util.DisplayMetrics;
import android.util.Singleton;
import android.util.Size;
-import android.window.IWindowContainer;
+import android.window.WindowContainerToken;
import android.view.Surface;
import com.android.internal.app.LocalePicker;
@@ -2759,7 +2759,7 @@
// Index of the stack in the display's stack list, can be used for comparison of stack order
@UnsupportedAppUsage
public int position;
- public IWindowContainer stackToken;
+ public WindowContainerToken stackToken;
/**
* The full configuration the stack is currently running in.
* @hide
@@ -2793,7 +2793,7 @@
dest.writeInt(userId);
dest.writeInt(visible ? 1 : 0);
dest.writeInt(position);
- dest.writeStrongInterface(stackToken);
+ stackToken.writeToParcel(dest, 0);
if (topActivity != null) {
dest.writeInt(1);
topActivity.writeToParcel(dest, 0);
@@ -2825,7 +2825,7 @@
userId = source.readInt();
visible = source.readInt() > 0;
position = source.readInt();
- stackToken = IWindowContainer.Stub.asInterface(source.readStrongBinder());
+ stackToken = WindowContainerToken.CREATOR.createFromParcel(source);
if (source.readInt() > 0) {
topActivity = ComponentName.readFromParcel(source);
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 073b8d0..ab7925c 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -42,6 +42,9 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.window.TaskEmbedder;
+import android.window.TaskOrganizerTaskEmbedder;
+import android.window.VirtualDisplayTaskEmbedder;
import dalvik.system.CloseGuard;
@@ -52,11 +55,11 @@
* @hide
*/
@TestApi
-public class ActivityView extends ViewGroup implements TaskEmbedder.Host {
+public class ActivityView extends ViewGroup implements android.window.TaskEmbedder.Host {
private static final String TAG = "ActivityView";
- private TaskEmbedder mTaskEmbedder;
+ private android.window.TaskEmbedder mTaskEmbedder;
private final SurfaceView mSurfaceView;
private final SurfaceCallback mSurfaceCallback;
@@ -487,7 +490,7 @@
/** @hide */
@Override
- public void onTaskBackgroundColorChanged(TaskEmbedder ts, int bgColor) {
+ public void onTaskBackgroundColorChanged(android.window.TaskEmbedder ts, int bgColor) {
if (mSurfaceView != null) {
mSurfaceView.setResizeBackgroundColor(bgColor);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9b42fa2..f461a17 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1232,6 +1232,10 @@
/** @hide */
public static final String EXTRA_CONVERSATION_ICON = "android.conversationIcon";
+ /** @hide */
+ public static final String EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT =
+ "android.conversationUnreadMessageCount";
+
/**
* {@link #extras} key: an array of {@link android.app.Notification.MessagingStyle.Message}
* bundles provided by a
@@ -7102,6 +7106,7 @@
List<Message> mHistoricMessages = new ArrayList<>();
boolean mIsGroupConversation;
@ConversationType int mConversationType = CONVERSATION_TYPE_LEGACY;
+ int mUnreadMessageCount;
MessagingStyle() {
}
@@ -7247,6 +7252,17 @@
return mConversationType;
}
+ /** @hide */
+ public int getUnreadMessageCount() {
+ return mUnreadMessageCount;
+ }
+
+ /** @hide */
+ public MessagingStyle setUnreadMessageCount(int unreadMessageCount) {
+ mUnreadMessageCount = unreadMessageCount;
+ return this;
+ }
+
/**
* Adds a message for display by this notification. Convenience call for a simple
* {@link Message} in {@link #addMessage(Notification.MessagingStyle.Message)}.
@@ -7401,6 +7417,7 @@
if (mShortcutIcon != null) {
extras.putParcelable(EXTRA_CONVERSATION_ICON, mShortcutIcon);
}
+ extras.putInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT, mUnreadMessageCount);
fixTitleAndTextExtras(extras);
extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, mIsGroupConversation);
@@ -7452,6 +7469,7 @@
Parcelable[] histMessages = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES);
mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
mIsGroupConversation = extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION);
+ mUnreadMessageCount = extras.getInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
}
/**
@@ -7601,6 +7619,7 @@
: mBuilder.getMessagingLayoutResource(),
p,
bindResult);
+
addExtras(mBuilder.mN.extras);
if (!isConversationLayout) {
// also update the end margin if there is an image
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 7c0fc42..0173731 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -28,7 +28,7 @@
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
-import android.window.IWindowContainer;
+import android.window.WindowContainerToken;
/**
* Stores information about a particular Task.
@@ -147,7 +147,7 @@
* @hide
*/
@NonNull
- public IWindowContainer token;
+ public WindowContainerToken token;
/**
* The PictureInPictureParams for the Task, if set.
@@ -222,7 +222,7 @@
supportsSplitScreenMultiWindow = source.readBoolean();
resizeMode = source.readInt();
configuration.readFromParcel(source);
- token = IWindowContainer.Stub.asInterface(source.readStrongBinder());
+ token = WindowContainerToken.CREATOR.createFromParcel(source);
topActivityType = source.readInt();
pictureInPictureParams = source.readInt() != 0
? PictureInPictureParams.CREATOR.createFromParcel(source)
@@ -265,7 +265,7 @@
dest.writeBoolean(supportsSplitScreenMultiWindow);
dest.writeInt(resizeMode);
configuration.writeToParcel(dest, flags);
- dest.writeStrongInterface(token);
+ token.writeToParcel(dest, flags);
dest.writeInt(topActivityType);
if (pictureInPictureParams == null) {
dest.writeInt(0);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 5bad055..8bebaff 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -306,6 +306,35 @@
void setHomeActivity(in ComponentName className, int userId);
/**
+ * Overrides the label and icon of the component specified by the component name. The component
+ * must belong to the calling app.
+ *
+ * These changes will be reset on the next boot and whenever the package is updated.
+ *
+ * Only the app defined as com.android.internal.R.config_overrideComponentUiPackage is allowed
+ * to call this.
+ *
+ * @param componentName The component name to override the label/icon of.
+ * @param nonLocalizedLabel The label to be displayed.
+ * @param icon The icon to be displayed.
+ * @param userId The user id.
+ */
+ void overrideLabelAndIcon(in ComponentName componentName, String nonLocalizedLabel,
+ int icon, int userId);
+
+ /**
+ * Restores the label and icon of the activity specified by the component name if either has
+ * been overridden. The component must belong to the calling app.
+ *
+ * Only the app defined as com.android.internal.R.config_overrideComponentUiPackage is allowed
+ * to call this.
+ *
+ * @param componentName The component name.
+ * @param userId The user id.
+ */
+ void restoreLabelAndIcon(in ComponentName componentName, int userId);
+
+ /**
* As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
*/
@UnsupportedAppUsage
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 61b1553..327d1b8 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -27,18 +27,24 @@
import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.os.BaseBundle;
import android.os.Debug;
import android.os.PersistableBundle;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
+import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -84,6 +90,9 @@
private ArrayMap<String, String[]> sharedLibraryOverlayPaths; // Lib name to overlay paths
private String[] cachedOverlayPaths;
+ @Nullable
+ private ArrayMap<ComponentName, Pair<String, Integer>> componentLabelIconOverrideMap;
+
@UnsupportedAppUsage
public PackageUserState() {
installed = true;
@@ -123,6 +132,9 @@
sharedLibraryOverlayPaths = new ArrayMap<>(o.sharedLibraryOverlayPaths);
}
harmfulAppWarning = o.harmfulAppWarning;
+ if (o.componentLabelIconOverrideMap != null) {
+ this.componentLabelIconOverrideMap = new ArrayMap<>(o.componentLabelIconOverrideMap);
+ }
}
public String[] getOverlayPaths() {
@@ -147,6 +159,65 @@
}
/**
+ * Overrides the non-localized label and icon of a component.
+ *
+ * @return true if the label or icon was changed.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public boolean overrideLabelAndIcon(@NonNull ComponentName component,
+ @Nullable String nonLocalizedLabel, @Nullable Integer icon) {
+ String existingLabel = null;
+ Integer existingIcon = null;
+
+ if (componentLabelIconOverrideMap != null) {
+ Pair<String, Integer> pair = componentLabelIconOverrideMap.get(component);
+ if (pair != null) {
+ existingLabel = pair.first;
+ existingIcon = pair.second;
+ }
+ }
+
+ boolean changed = !TextUtils.equals(existingLabel, nonLocalizedLabel)
+ || !Objects.equals(existingIcon, icon);
+
+ if (changed) {
+ if (nonLocalizedLabel == null && icon == null) {
+ componentLabelIconOverrideMap.remove(component);
+ if (componentLabelIconOverrideMap.isEmpty()) {
+ componentLabelIconOverrideMap = null;
+ }
+ } else {
+ if (componentLabelIconOverrideMap == null) {
+ componentLabelIconOverrideMap = new ArrayMap<>(1);
+ }
+
+ componentLabelIconOverrideMap.put(component, Pair.create(nonLocalizedLabel, icon));
+ }
+ }
+
+ return changed;
+ }
+
+ /**
+ * Clears all values previously set by {@link #overrideLabelAndIcon(ComponentName,
+ * String, Integer)}.
+ *
+ * This is done when the package is updated as the components and resource IDs may have changed.
+ */
+ public void resetOverrideComponentLabelIcon() {
+ componentLabelIconOverrideMap = null;
+ }
+
+ @Nullable
+ public Pair<String, Integer> getOverrideLabelIconForComponent(ComponentName componentName) {
+ if (ArrayUtils.isEmpty(componentLabelIconOverrideMap)) {
+ return null;
+ }
+
+ return componentLabelIconOverrideMap.get(componentName);
+ }
+
+ /**
* Test if this package is installed.
*/
public boolean isAvailable(int flags) {
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 435c70a..eee91ce1 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -109,4 +109,8 @@
*/
public abstract String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId);
+
+ public abstract boolean isSharingShortcut(int callingUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId,
+ @NonNull IntentFilter filter);
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index e90ccdf..12328cf 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -65,7 +65,9 @@
import android.content.pm.parsing.component.ParsedService;
import android.content.pm.parsing.component.ParsedServiceUtils;
import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseInput.DeferredError;
import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
@@ -126,6 +128,51 @@
public static final String TAG = ParsingUtils.TAG;
+ /**
+ * For cases outside of PackageManagerService when an APK needs to be parsed as a one-off
+ * request, without caching the input object and without querying the internal system state
+ * for feature support.
+ */
+ @NonNull
+ public static ParseResult<ParsingPackage> parseDefaultOneTime(File file, int flags,
+ @NonNull ParseInput.Callback inputCallback, @NonNull Callback callback) {
+ if ((flags & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
+ // Caller expressed no opinion about what encryption
+ // aware/unaware components they want to see, so match both
+ flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ }
+
+ ParseInput input = new ParseTypeImpl(inputCallback).reset();
+ ParseResult<ParsingPackage> result;
+
+
+ ParsingPackageUtils parser = new ParsingPackageUtils(false, null, null, callback);
+ try {
+ result = parser.parsePackage(input, file, flags);
+ if (result.isError()) {
+ return result;
+ }
+ } catch (PackageParser.PackageParserException e) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Error parsing package", e);
+ }
+
+ try {
+ ParsingPackage pkg = result.getResult();
+ if ((flags & PackageManager.GET_SIGNATURES) != 0
+ || (flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
+ ParsingPackageUtils.collectCertificates(pkg, false /* skipVerify */);
+ }
+
+ return input.success(pkg);
+ } catch (PackageParser.PackageParserException e) {
+ return input.error(PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
+ "Error collecting package certificates", e);
+ }
+ }
+
private boolean mOnlyCoreApps;
private String[] mSeparateProcesses;
private DisplayMetrics mDisplayMetrics;
@@ -456,10 +503,11 @@
}
if (!foundApp) {
- return input.error(
- PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
- "<manifest> does not contain an <application>"
- );
+ ParseResult<?> deferResult = input.deferError(
+ "<manifest> does not contain an <application>", DeferredError.MISSING_APP_TAG);
+ if (deferResult.isError()) {
+ return input.error(deferResult);
+ }
}
return input.success(pkg);
@@ -663,10 +711,12 @@
}
if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {
- return input.error(
- PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY,
- "<manifest> does not contain an <application> or <instrumentation>"
- );
+ ParseResult<?> deferResult = input.deferError(
+ "<manifest> does not contain an <application> or <instrumentation>",
+ DeferredError.MISSING_APP_TAG);
+ if (deferResult.isError()) {
+ return input.error(deferResult);
+ }
}
if (!ParsedAttribution.isCombinationValid(pkg.getAttributions())) {
@@ -758,11 +808,9 @@
return input.success(pkg);
}
- ParseResult nameResult = validateName(input, str, true, true);
- if (nameResult.isError()) {
- if ("android".equals(pkg.getPackageName())) {
- nameResult.ignoreError();
- } else {
+ if (!"android".equals(pkg.getPackageName())) {
+ ParseResult<?> nameResult = validateName(input, str, true, true);
+ if (nameResult.isError()) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
"<manifest> specifies bad sharedUserId name \"" + str + "\": "
+ nameResult.getErrorMessage());
@@ -1166,6 +1214,20 @@
targetCode = minCode;
}
+ ParseResult<Integer> targetSdkVersionResult = computeTargetSdkVersion(
+ targetVers, targetCode, PackageParser.SDK_CODENAMES, input);
+ if (targetSdkVersionResult.isError()) {
+ return input.error(targetSdkVersionResult);
+ }
+
+ int targetSdkVersion = targetSdkVersionResult.getResult();
+
+ ParseResult<?> deferResult =
+ input.enableDeferredError(pkg.getPackageName(), targetSdkVersion);
+ if (deferResult.isError()) {
+ return input.error(deferResult);
+ }
+
ParseResult<Integer> minSdkVersionResult = computeMinSdkVersion(minVers, minCode,
PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, input);
if (minSdkVersionResult.isError()) {
@@ -1174,14 +1236,6 @@
int minSdkVersion = minSdkVersionResult.getResult();
- ParseResult<Integer> targetSdkVersionResult = computeTargetSdkVersion(
- targetVers, targetCode, PackageParser.SDK_CODENAMES, input);
- if (targetSdkVersionResult.isError()) {
- return input.error(targetSdkVersionResult);
- }
-
- int targetSdkVersion = minSdkVersionResult.getResult();
-
pkg.setMinSdkVersion(minSdkVersion)
.setTargetSdkVersion(targetSdkVersion);
@@ -1763,9 +1817,15 @@
// Add a hidden app detail activity to normal apps which forwards user to App Details
// page.
ParseResult<ParsedActivity> a = generateAppDetailsHiddenActivity(input, pkg);
- // Backwards-compat, assume success
+ if (a.isError()) {
+ // Error should be impossible here, as the only failure case as of SDK R is a
+ // string validation error on a constant ":app_details" string passed in by the
+ // parsing code itself. For this reason, this is just a hard failure instead of
+ // deferred.
+ return input.error(a);
+ }
+
pkg.addActivity(a.getResult());
- a.ignoreError();
}
if (hasActivityOrder) {
@@ -2122,18 +2182,14 @@
private static ParseResult<ParsedActivity> generateAppDetailsHiddenActivity(ParseInput input,
ParsingPackage pkg) {
String packageName = pkg.getPackageName();
- ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
+ ParseResult<String> result = ComponentParseUtils.buildTaskAffinityName(
packageName, packageName, ":app_details", input);
-
- String taskAffinity;
- if (taskAffinityResult.isSuccess()) {
- taskAffinity = taskAffinityResult.getResult();
- } else {
- // Backwards-compat, do not fail
- taskAffinity = null;
- taskAffinityResult.ignoreError();
+ if (result.isError()) {
+ return input.error(result);
}
+ String taskAffinity = result.getResult();
+
// Build custom App Details activity info instead of parsing it from xml
return input.success(ParsedActivity.makeAppDetailsActivity(packageName,
pkg.getProcessName(), pkg.getUiOptions(), taskAffinity,
@@ -2688,7 +2744,8 @@
public interface Callback {
boolean hasFeature(String feature);
- ParsingPackage startParsingPackage(String packageName, String baseCodePath, String codePath,
+ ParsingPackage startParsingPackage(@NonNull String packageName,
+ @NonNull String baseCodePath, @NonNull String codePath,
@NonNull TypedArray manifestArray, boolean isCoreApp);
}
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 6e5c51a..f64560a 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -179,13 +179,12 @@
ParseResult<String> affinityNameResult = ComponentParseUtils.buildTaskAffinityName(
packageName, pkg.getTaskAffinity(), taskAffinity, input);
- if (affinityNameResult.isSuccess()) {
- activity.taskAffinity = affinityNameResult.getResult();
- } else {
- // Backwards-compat, ignore error
- affinityNameResult.ignoreError();
+ if (affinityNameResult.isError()) {
+ return input.error(affinityNameResult);
}
+ activity.taskAffinity = affinityNameResult.getResult();
+
boolean visibleToEphemeral = sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
if (visibleToEphemeral) {
activity.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
index a7b950b..390f769 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
@@ -29,7 +29,6 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.PatternMatcher;
-import android.text.TextUtils;
import android.util.Slog;
import android.util.TypedValue;
@@ -97,8 +96,13 @@
case "action": {
String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
"name");
- if (TextUtils.isEmpty(value)) {
+ if (value == null) {
result = input.error("No value supplied for <android:name>");
+ } else if (value.isEmpty()) {
+ intentInfo.addAction(value);
+ // Prior to R, this was not a failure
+ result = input.deferError("No value supplied for <android:name>",
+ ParseInput.DeferredError.EMPTY_INTENT_ACTION_CATEGORY);
} else {
intentInfo.addAction(value);
result = input.success(null);
@@ -108,8 +112,13 @@
case "category": {
String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
"name");
- if (TextUtils.isEmpty(value)) {
+ if (value == null) {
result = input.error("No value supplied for <android:name>");
+ } else if (value.isEmpty()) {
+ intentInfo.addCategory(value);
+ // Prior to R, this was not a failure
+ result = input.deferError("No value supplied for <android:name>",
+ ParseInput.DeferredError.EMPTY_INTENT_ACTION_CATEGORY);
} else {
intentInfo.addCategory(value);
result = input.success(null);
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
index 6188f89..f4c9914 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
@@ -20,6 +20,9 @@
import android.annotation.Nullable;
import android.content.IntentFilter;
import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -28,9 +31,6 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.result.ParseInput;
-import android.content.pm.parsing.result.ParseResult;
import org.xmlpull.v1.XmlPullParserException;
@@ -83,12 +83,11 @@
ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
pkg.getPackageName(), pkg.getProcessName(), processName, flags,
separateProcesses, input);
- if (processNameResult.isSuccess()) {
- component.setProcessName(processNameResult.getResult());
- } else {
- // Backwards-compat, ignore error
- processNameResult.ignoreError();
+ if (processNameResult.isError()) {
+ return input.error(processNameResult);
}
+
+ component.setProcessName(processNameResult.getResult());
}
if (splitNameAttr != null) {
diff --git a/core/java/android/content/pm/parsing/result/ParseInput.java b/core/java/android/content/pm/parsing/result/ParseInput.java
index c468506..5385100 100644
--- a/core/java/android/content/pm/parsing/result/ParseInput.java
+++ b/core/java/android/content/pm/parsing/result/ParseInput.java
@@ -16,10 +16,12 @@
package android.content.pm.parsing.result;
-import android.annotation.Hide;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.pm.PackageManager;
+import android.os.Build;
/**
* Used as a method parameter which is then transformed into a {@link ParseResult}. This is
@@ -30,8 +32,52 @@
*/
public interface ParseInput {
+ /**
+ * Errors encountered during parsing may rely on the targetSDK version of the application to
+ * determine whether or not to fail. These are passed into {@link #deferError(String, long)}
+ * when encountered, and the implementation will handle how to defer the errors until the
+ * targetSdkVersion is known and sent to {@link #enableDeferredError(String, int)}.
+ *
+ * All of these must be marked {@link ChangeId}, as that is the mechanism used to check if the
+ * error must be propagated. This framework also allows developers to pre-disable specific
+ * checks if they wish to target a newer SDK version in a development environment without
+ * having to migrate their entire app to validate on a newer platform.
+ */
+ final class DeferredError {
+ /**
+ * Missing an "application" or "instrumentation" tag.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ public static final long MISSING_APP_TAG = 150776642;
+
+ /**
+ * An intent filter's actor or category is an empty string. A bug in the platform before R
+ * allowed this to pass through without an error. This does not include cases when the
+ * attribute is null/missing, as that has always been a failure.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ public static final long EMPTY_INTENT_ACTION_CATEGORY = 151163173;
+ }
+
<ResultType> ParseResult<ResultType> success(ResultType result);
+ /**
+ * Used for errors gated by {@link DeferredError}. Will return an error result if the
+ * targetSdkVersion is already known and this must be returned as a real error. The result
+ * contains null and should not be unwrapped.
+ *
+ * @see #error(String)
+ */
+ ParseResult<?> deferError(@NonNull String parseError, long deferredError);
+
+ /**
+ * Called after targetSdkVersion is known. Returns an error result if a previously deferred
+ * error was registered. The result contains null and should not be unwrapped.
+ */
+ ParseResult<?> enableDeferredError(String packageName, int targetSdkVersion);
+
/** @see #error(int, String, Exception) */
<ResultType> ParseResult<ResultType> error(int parseError);
@@ -52,9 +98,6 @@
* The calling site of that method is then expected to check the result for error, and
* continue to bubble up if it is an error.
*
- * Or, if the code explicitly handles an error,
- * {@link ParseResult#ignoreError()} should be called.
- *
* If the result {@link ParseResult#isSuccess()}, then it can be used as-is, as
* overlapping/consecutive successes are allowed.
*/
@@ -66,5 +109,17 @@
* but cast the type of the {@link ParseResult} for type safety, since the parameter
* and the receiver should be the same object.
*/
- <ResultType> ParseResult<ResultType> error(ParseResult result);
+ <ResultType> ParseResult<ResultType> error(ParseResult<?> result);
+
+ /**
+ * Implemented instead of a direct reference to
+ * {@link com.android.internal.compat.IPlatformCompat}, allowing caching and testing logic to
+ * be separated out.
+ */
+ interface Callback {
+ /**
+ * @return true if the changeId should be enabled
+ */
+ boolean isChangeEnabled(long changeId, @NonNull String packageName, int targetSdkVersion);
+ }
}
diff --git a/core/java/android/content/pm/parsing/result/ParseResult.java b/core/java/android/content/pm/parsing/result/ParseResult.java
index 338048c..518395d 100644
--- a/core/java/android/content/pm/parsing/result/ParseResult.java
+++ b/core/java/android/content/pm/parsing/result/ParseResult.java
@@ -17,32 +17,19 @@
package android.content.pm.parsing.result;
import android.annotation.Nullable;
-import android.content.pm.PackageParser;
/**
* The output side of {@link ParseInput}, which must result from a method call on
* {@link ParseInput}.
*
* When using this class, keep in mind that all {@link ParseInput}s and {@link ParseResult}s
- * are the exact same object, scoped to a per {@link PackageParser} instance, per thread basis,
- * thrown around and casted everywhere for type safety.
+ * are the exact same object, scoped per thread, thrown around and casted for type safety.
*
* @hide
*/
public interface ParseResult<ResultType> {
/**
- * Un-marks this result as an error, also allowing it to be re-used as {@link ParseInput}.
- *
- * This should only be used in cases where it's absolutely certain that error handling is
- * irrelevant. Such as for backwards compatibility where it previously didn't fail and that
- * behavior has to be maintained.
- *
- * Mostly an alias for readability.
- */
- void ignoreError();
-
- /**
* Returns true if the result is not an error and thus contains a valid object.
*
* For backwards-compat reasons, it's possible to have a successful result with a null
diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
index 9b22f09..b26bf71 100644
--- a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -20,51 +20,130 @@
import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ParsingUtils;
+import android.util.ArrayMap;
import android.util.Log;
+import android.util.Slog;
-import java.util.Arrays;
+import com.android.internal.util.CollectionUtils;
/** @hide */
public class ParseTypeImpl implements ParseInput, ParseResult<Object> {
private static final String TAG = ParsingUtils.TAG;
- private static final boolean DEBUG_FILL_STACK_TRACE = false;
+ public static final boolean DEBUG_FILL_STACK_TRACE = false;
- private static final boolean DEBUG_LOG_ON_ERROR = false;
+ public static final boolean DEBUG_LOG_ON_ERROR = false;
- private Object result;
+ public static final boolean DEBUG_THROW_ALL_ERRORS = false;
- private int errorCode = PackageManager.INSTALL_SUCCEEDED;
+ @NonNull
+ private Callback mCallback;
+
+ private Object mResult;
+
+ private int mErrorCode = PackageManager.INSTALL_SUCCEEDED;
@Nullable
- private String errorMessage;
+ private String mErrorMessage;
@Nullable
- private Exception exception;
+ private Exception mException;
+
+ /**
+ * Errors encountered before targetSdkVersion is known.
+ * The size upper bound is the number of longs in {@link DeferredError}
+ */
+ @Nullable
+ private ArrayMap<Long, String> mDeferredErrors = null;
+
+ private String mPackageName;
+ private Integer mTargetSdkVersion;
+
+ /**
+ * @param callback if nullable, fallback to manual targetSdk > Q check
+ */
+ public ParseTypeImpl(@NonNull Callback callback) {
+ mCallback = callback;
+ }
public ParseInput reset() {
- this.result = null;
- this.errorCode = PackageManager.INSTALL_SUCCEEDED;
- this.errorMessage = null;
- this.exception = null;
+ mResult = null;
+ mErrorCode = PackageManager.INSTALL_SUCCEEDED;
+ mErrorMessage = null;
+ mException = null;
+ if (mDeferredErrors != null) {
+ // If the memory was already allocated, don't bother freeing and re-allocating,
+ // as this could occur hundreds of times depending on what the caller is doing and
+ // how many APKs they're going through.
+ mDeferredErrors.erase();
+ }
return this;
}
@Override
- public void ignoreError() {
- reset();
+ public <ResultType> ParseResult<ResultType> success(ResultType result) {
+ if (mErrorCode != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.wtf(ParsingUtils.TAG, "Cannot set to success after set to error, was "
+ + mErrorMessage, mException);
+ }
+ mResult = result;
+ //noinspection unchecked
+ return (ParseResult<ResultType>) this;
}
@Override
- public <ResultType> ParseResult<ResultType> success(ResultType result) {
- if (errorCode != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) {
- throw new IllegalStateException("Cannot set to success after set to error, was "
- + errorMessage, exception);
+ public ParseResult<?> deferError(@NonNull String parseError, long deferredError) {
+ if (DEBUG_THROW_ALL_ERRORS) {
+ return error(parseError);
}
- this.result = result;
- //noinspection unchecked
- return (ParseResult<ResultType>) this;
+ if (mTargetSdkVersion != null) {
+ if (mDeferredErrors != null && mDeferredErrors.containsKey(deferredError)) {
+ // If the map already contains the key, that means it's already been checked and
+ // found to be disabled. Otherwise it would've failed when mTargetSdkVersion was
+ // set to non-null.
+ return success(null);
+ }
+
+ if (mCallback.isChangeEnabled(deferredError, mPackageName, mTargetSdkVersion)) {
+ return error(parseError);
+ } else {
+ if (mDeferredErrors == null) {
+ mDeferredErrors = new ArrayMap<>();
+ }
+ mDeferredErrors.put(deferredError, null);
+ return success(null);
+ }
+ }
+
+ if (mDeferredErrors == null) {
+ mDeferredErrors = new ArrayMap<>();
+ }
+
+ // Only save the first occurrence of any particular error
+ mDeferredErrors.putIfAbsent(deferredError, parseError);
+ return success(null);
+ }
+
+ @Override
+ public ParseResult<?> enableDeferredError(String packageName, int targetSdkVersion) {
+ mPackageName = packageName;
+ mTargetSdkVersion = targetSdkVersion;
+
+ int size = CollectionUtils.size(mDeferredErrors);
+ for (int index = size - 1; index >= 0; index--) {
+ long changeId = mDeferredErrors.keyAt(index);
+ String errorMessage = mDeferredErrors.valueAt(index);
+ if (mCallback.isChangeEnabled(changeId, mPackageName, mTargetSdkVersion)) {
+ return error(errorMessage);
+ } else {
+ // No point holding onto the string, but need to maintain the key to signal
+ // that the error was checked with isChangeEnabled and found to be disabled.
+ mDeferredErrors.setValueAt(index, null);
+ }
+ }
+
+ return success(null);
}
@Override
@@ -84,25 +163,26 @@
}
@Override
- public <ResultType> ParseResult<ResultType> error(ParseResult intentResult) {
- return error(intentResult.getErrorCode(), intentResult.getErrorMessage());
+ public <ResultType> ParseResult<ResultType> error(ParseResult<?> intentResult) {
+ return error(intentResult.getErrorCode(), intentResult.getErrorMessage(),
+ intentResult.getException());
}
@Override
public <ResultType> ParseResult<ResultType> error(int errorCode, @Nullable String errorMessage,
Exception exception) {
- this.errorCode = errorCode;
- this.errorMessage = errorMessage;
- this.exception = exception;
+ mErrorCode = errorCode;
+ mErrorMessage = errorMessage;
+ mException = exception;
if (DEBUG_FILL_STACK_TRACE) {
if (exception == null) {
- this.exception = new Exception();
+ mException = new Exception();
}
}
if (DEBUG_LOG_ON_ERROR) {
- Exception exceptionToLog = this.exception != null ? this.exception : new Exception();
+ Exception exceptionToLog = mException != null ? mException : new Exception();
Log.w(TAG, "ParseInput set to error " + errorCode + ", " + errorMessage,
exceptionToLog);
}
@@ -113,12 +193,12 @@
@Override
public Object getResult() {
- return this.result;
+ return mResult;
}
@Override
public boolean isSuccess() {
- return errorCode == PackageManager.INSTALL_SUCCEEDED;
+ return mErrorCode == PackageManager.INSTALL_SUCCEEDED;
}
@Override
@@ -128,18 +208,18 @@
@Override
public int getErrorCode() {
- return errorCode;
+ return mErrorCode;
}
@Nullable
@Override
public String getErrorMessage() {
- return errorMessage;
+ return mErrorMessage;
}
@Nullable
@Override
public Exception getException() {
- return exception;
+ return mException;
}
}
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 34cc856..9b809b8 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -43,6 +43,7 @@
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.text.Collator;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -308,6 +309,34 @@
}
/**
+ * Make a deep copy of the given argument list, ensuring that the returned
+ * value is completely isolated from any changes to the original arguments.
+ *
+ * @hide
+ */
+ public static @Nullable Object[] deepCopyOf(@Nullable Object[] args) {
+ if (args == null) return null;
+
+ final Object[] res = new Object[args.length];
+ for (int i = 0; i < args.length; i++) {
+ final Object arg = args[i];
+
+ if ((arg == null) || (arg instanceof Number) || (arg instanceof String)) {
+ // When the argument is immutable, we can copy by reference
+ res[i] = arg;
+ } else if (arg instanceof byte[]) {
+ // Need to deep copy blobs
+ final byte[] castArg = (byte[]) arg;
+ res[i] = Arrays.copyOf(castArg, castArg.length);
+ } else {
+ // Convert everything else to string, making it immutable
+ res[i] = String.valueOf(arg);
+ }
+ }
+ return res;
+ }
+
+ /**
* Returns data type of the given object's value.
*<p>
* Returned values are
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 24ac152..7c4692c 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1066,6 +1066,10 @@
throws SQLException {
Objects.requireNonNull(sql);
+ // Copy arguments to ensure that the caller doesn't accidentally change
+ // the values used by future connections
+ bindArgs = DatabaseUtils.deepCopyOf(bindArgs);
+
synchronized (mLock) {
throwIfNotOpenLocked();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index cdc0019..b8e1aa8 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -32,6 +32,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.service.dreams.Sandman;
+import android.sysprop.InitProperties;
import android.util.ArrayMap;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -1487,7 +1488,7 @@
*/
// TODO(b/138605180): add link to documentation once it's ready.
public boolean isRebootingUserspaceSupported() {
- return SystemProperties.getBoolean("ro.init.userspace_reboot.is_supported", false);
+ return InitProperties.is_userspace_reboot_supported().orElse(false);
}
/**
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 2dbaea8..d8308c7 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -38,6 +38,13 @@
int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
/**
+ * Changes storage params. Returns 0 on success, and -errno on failure.
+ * Use enableReadLogs to switch pages read logs reporting on and off.
+ * Returns 0 on success, and - errno on failure: permission check or remount.
+ */
+ int setStorageParams(int storageId, boolean enableReadLogs);
+
+ /**
* Bind-mounts a path under a storage to a full path. Can be permanent or temporary.
*/
const int BIND_TEMPORARY = 0;
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 35518db..5f01408 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -19,11 +19,13 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.content.pm.DataLoaderParams;
import android.content.pm.IDataLoaderStatusListener;
import android.os.RemoteException;
+import android.system.ErrnoException;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -319,6 +321,23 @@
return nativeUnsafeGetFileSignature(path);
}
+ /**
+ * Sets storage parameters.
+ *
+ * @param enableReadLogs - enables or disables read logs. Caller has to have a permission.
+ */
+ @RequiresPermission(android.Manifest.permission.LOADER_USAGE_STATS)
+ public void setStorageParams(int storageId, boolean enableReadLogs) throws ErrnoException {
+ try {
+ int res = mService.setStorageParams(storageId, enableReadLogs);
+ if (res < 0) {
+ throw new ErrnoException("setStorageParams", -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
/* Native methods */
private static native boolean nativeIsEnabled();
private static native boolean nativeIsIncrementalPath(@NonNull String path);
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index c047dc0..05877a5 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -21,6 +21,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.DataLoaderParams;
import android.content.pm.DataLoaderParamsParcel;
@@ -31,6 +32,8 @@
import android.content.pm.InstallationFileParcel;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.incremental.IncrementalManager;
+import android.system.ErrnoException;
import android.util.ExceptionUtils;
import android.util.Slog;
@@ -208,6 +211,25 @@
private final long mNativeInstance;
}
+ /* Used by native FileSystemConnector. */
+ private boolean setStorageParams(int storageId, boolean enableReadLogs) {
+ IncrementalManager incrementalManager = (IncrementalManager) getSystemService(
+ Context.INCREMENTAL_SERVICE);
+ if (incrementalManager == null) {
+ Slog.e(TAG, "Failed to obtain incrementalManager: " + storageId);
+ return false;
+ }
+ try {
+ // This has to be done directly in incrementalManager as the storage
+ // might be missing still.
+ incrementalManager.setStorageParams(storageId, enableReadLogs);
+ } catch (ErrnoException e) {
+ Slog.e(TAG, "Failed to set params for storage: " + storageId, e);
+ return false;
+ }
+ return true;
+ }
+
/* Native methods */
private native boolean nativeCreateDataLoader(int storageId,
@NonNull FileSystemControlParcel control,
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 41fdd0b..7bf5c38 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -49,6 +49,12 @@
* Called by the ActivityTaskManagerService to verify that the startDreamActivity
* request comes from the current active dream component.
*
+ * This function and its call path should not acquire the DreamManagerService lock
+ * to avoid deadlock with the ActivityTaskManager lock.
+ *
+ * TODO: Make this interaction push-based - the DreamManager should inform the
+ * ActivityTaskManager whenever the active dream component changes.
+ *
* @param doze If true returns the current active doze component. Otherwise, returns the
* active dream component.
*/
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7734ffb..0db9771 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1054,6 +1054,7 @@
// DreamServiceWrapper.onActivityCreated.
if (!mWindowless) {
Intent i = new Intent(this, DreamActivity.class);
+ i.setPackage(getApplicationContext().getPackageName());
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper);
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 35286ba..2461e96 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -16,7 +16,6 @@
package android.view;
-import static android.view.InsetsController.ANIMATION_TYPE_USER;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsState.ITYPE_IME;
@@ -104,13 +103,9 @@
void hide(boolean animationFinished, @AnimationType int animationType) {
super.hide();
- if (!animationFinished) {
- if (animationType == ANIMATION_TYPE_USER) {
- // if controlWindowInsetsAnimation is hiding keyboard.
- notifyHidden();
- }
- } else {
+ if (animationFinished) {
// remove IME surface as IME has finished hide animation.
+ notifyHidden();
removeSurface();
}
}
diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java
index 4227f78..74c1869 100644
--- a/core/java/android/view/InsetsAnimationControlCallbacks.java
+++ b/core/java/android/view/InsetsAnimationControlCallbacks.java
@@ -40,8 +40,10 @@
/**
* Schedule the apply by posting the animation callback.
+ *
+ * @param runner The runner that requested applying insets
*/
- void scheduleApplyChangeInsets();
+ void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner);
/**
* Finish the final steps after the animation.
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 94ca550..05abc60 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -140,7 +140,12 @@
@Override
public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) {
- if (mFinished) {
+ setInsetsAndAlpha(insets, alpha, fraction, false /* allowWhenFinished */);
+ }
+
+ private void setInsetsAndAlpha(Insets insets, float alpha, float fraction,
+ boolean allowWhenFinished) {
+ if (!allowWhenFinished && mFinished) {
throw new IllegalStateException(
"Can't change insets on an animation that is finished.");
}
@@ -151,7 +156,7 @@
mPendingFraction = sanitize(fraction);
mPendingInsets = sanitize(insets);
mPendingAlpha = sanitize(alpha);
- mController.scheduleApplyChangeInsets();
+ mController.scheduleApplyChangeInsets(this);
}
@VisibleForTesting
@@ -201,8 +206,9 @@
return;
}
mShownOnFinish = shown;
- setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */);
mFinished = true;
+ setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */,
+ true /* allowWhenFinished */);
mListener.onFinished(this);
}
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 40ffa7ef..9dfdd06 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -54,7 +54,7 @@
}
@Override
- public void scheduleApplyChangeInsets() {
+ public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) {
mControl.applyChangeInsets(mState);
}
@@ -91,7 +91,7 @@
@AnimationType int animationType, Handler mainThreadHandler) {
mMainThreadHandler = mainThreadHandler;
mOuterCallbacks = controller;
- mControl = new InsetsAnimationControlImpl(copyControls(controls), frame, state, listener,
+ mControl = new InsetsAnimationControlImpl(controls, frame, state, listener,
types, mCallbacks, durationMs, interpolator, animationType);
InsetsAnimationThread.getHandler().post(() -> listener.onReady(mControl, types));
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8eb9b5f..72ddaca 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1076,8 +1076,8 @@
@VisibleForTesting
@Override
- public void scheduleApplyChangeInsets() {
- if (mStartingAnimation) {
+ public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) {
+ if (mStartingAnimation || runner.getAnimationType() == ANIMATION_TYPE_USER) {
mAnimCallback.run();
mAnimCallbackScheduled = false;
return;
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 83ff8fa..f74221d 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -117,7 +117,7 @@
}
}
if (lastControl != null) {
- lastControl.release(mController::releaseSurfaceControlFromRt);
+ lastControl.release(SurfaceControl::release);
}
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index c515466..9896aa4 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -172,6 +172,10 @@
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
InsetsSource source = mSources.get(type);
if (source == null) {
+ int index = indexOf(toPublicType(type));
+ if (typeInsetsMap[index] == null) {
+ typeInsetsMap[index] = Insets.NONE;
+ }
continue;
}
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 0359f3b4..a9f3e04 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -60,11 +60,7 @@
private NotificationExpandButton mExpandButton;
private CachingIconView mIcon;
private View mProfileBadge;
- private View mOverlayIcon;
- private View mCameraIcon;
- private View mMicIcon;
private View mAppOps;
- private View mAudiblyAlertedIcon;
private boolean mExpanded;
private boolean mShowExpandButtonAtEnd;
private boolean mShowWorkBadgeAtEnd;
@@ -121,11 +117,7 @@
mExpandButton = findViewById(com.android.internal.R.id.expand_button);
mIcon = findViewById(com.android.internal.R.id.icon);
mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
- mCameraIcon = findViewById(com.android.internal.R.id.camera);
- mMicIcon = findViewById(com.android.internal.R.id.mic);
- mOverlayIcon = findViewById(com.android.internal.R.id.overlay);
mAppOps = findViewById(com.android.internal.R.id.app_ops);
- mAudiblyAlertedIcon = findViewById(com.android.internal.R.id.alerted_icon);
}
@Override
@@ -300,10 +292,6 @@
*/
public void setAppOpsOnClickListener(OnClickListener l) {
mAppOpsListener = l;
- mAppOps.setOnClickListener(mAppOpsListener);
- mCameraIcon.setOnClickListener(mAppOpsListener);
- mMicIcon.setOnClickListener(mAppOpsListener);
- mOverlayIcon.setOnClickListener(mAppOpsListener);
updateTouchListener();
}
@@ -328,27 +316,6 @@
updateExpandButton();
}
- /**
- * Shows or hides 'app op in use' icons based on app usage.
- */
- public void showAppOpsIcons(ArraySet<Integer> appOps) {
- if (mOverlayIcon == null || mCameraIcon == null || mMicIcon == null || appOps == null) {
- return;
- }
-
- mOverlayIcon.setVisibility(appOps.contains(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
- ? View.VISIBLE : View.GONE);
- mCameraIcon.setVisibility(appOps.contains(AppOpsManager.OP_CAMERA)
- ? View.VISIBLE : View.GONE);
- mMicIcon.setVisibility(appOps.contains(AppOpsManager.OP_RECORD_AUDIO)
- ? View.VISIBLE : View.GONE);
- }
-
- /** Updates icon visibility based on the noisiness of the notification. */
- public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) {
- mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE);
- }
-
private void updateExpandButton() {
int drawableId;
int contentDescriptionId;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 51304dc..35f955f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -130,6 +130,7 @@
import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
+import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -1412,6 +1413,10 @@
| (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
}
+ if ((changes & LayoutParams.SOFT_INPUT_MODE_CHANGED) != 0) {
+ requestFitSystemWindows();
+ }
+
mWindowAttributesChanged = true;
scheduleTraversals();
}
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 9b2a6cb..ca3dd04 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -818,12 +818,13 @@
* @return A modified copy of this WindowInsets
* @deprecated Consuming of different parts individually of a {@link WindowInsets} instance is
* deprecated, since {@link WindowInsets} contains many different insets. Use {@link #CONSUMED}
- * instead to stop dispatching insets.
+ * instead to stop dispatching insets. On {@link android.os.Build.VERSION_CODES#R R}, this
+ * method has no effect.
*/
@Deprecated
@NonNull
public WindowInsets consumeStableInsets() {
- return consumeSystemWindowInsets();
+ return this;
}
/**
@@ -835,12 +836,24 @@
@Override
public String toString() {
- return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets()
- + " stableInsets=" + getStableInsets()
- + " sysGestureInsets=" + getSystemGestureInsets()
- + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
- + (isRound() ? " round" : "")
- + "}";
+ StringBuilder result = new StringBuilder("WindowInsets{\n ");
+ for (int i = 0; i < SIZE; i++) {
+ Insets insets = mTypeInsetsMap[i];
+ Insets maxInsets = mTypeMaxInsetsMap[i];
+ boolean visible = mTypeVisibilityMap[i];
+ if (!Insets.NONE.equals(insets) || !Insets.NONE.equals(maxInsets) || visible) {
+ result.append(Type.toString(1 << i)).append("=").append(insets)
+ .append(" max=").append(maxInsets)
+ .append(" vis=").append(visible)
+ .append("\n ");
+ }
+ }
+
+ result.append(mDisplayCutout != null ? "cutout=" + mDisplayCutout : "");
+ result.append("\n ");
+ result.append(isRound() ? "round" : "");
+ result.append("}");
+ return result.toString();
}
/**
@@ -1309,6 +1322,32 @@
}
}
+ static String toString(@InsetsType int type) {
+ switch (type) {
+ case STATUS_BARS:
+ return "statusBars";
+ case NAVIGATION_BARS:
+ return "navigationBars";
+ case CAPTION_BAR:
+ return "captionBar";
+ case IME:
+ return "ime";
+ case SYSTEM_GESTURES:
+ return "systemGestures";
+ case MANDATORY_SYSTEM_GESTURES:
+ return "mandatorySystemGestures";
+ case TAPPABLE_ELEMENT:
+ return "tappableElement";
+ case DISPLAY_CUTOUT:
+ return "displayCutout";
+ case WINDOW_DECOR:
+ return "windowDecor";
+ default:
+ throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
+ + " type=" + type);
+ }
+ }
+
private Type() {
}
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 6aa288d..af896fc 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -30,6 +30,7 @@
import com.android.internal.util.DataClass;
import com.android.internal.util.Preconditions;
+import com.android.internal.widget.InlinePresentationStyleUtils;
import java.util.ArrayList;
import java.util.List;
@@ -113,6 +114,10 @@
mHostInputToken = hostInputToken;
}
+ private boolean extrasEquals(@NonNull Bundle extras) {
+ return InlinePresentationStyleUtils.bundleEquals(mExtras, extras);
+ }
+
// TODO(b/149609075): remove once IBinder parcelling is natively supported
private void parcelHostInputToken(@NonNull Parcel parcel, int flags) {
parcel.writeStrongBinder(mHostInputToken);
@@ -331,7 +336,7 @@
&& java.util.Objects.equals(mInlinePresentationSpecs, that.mInlinePresentationSpecs)
&& java.util.Objects.equals(mHostPackageName, that.mHostPackageName)
&& java.util.Objects.equals(mSupportedLocales, that.mSupportedLocales)
- && java.util.Objects.equals(mExtras, that.mExtras)
+ && extrasEquals(that.mExtras)
&& java.util.Objects.equals(mHostInputToken, that.mHostInputToken)
&& mHostDisplayId == that.mHostDisplayId;
}
@@ -603,10 +608,10 @@
}
@DataClass.Generated(
- time = 1585691147541L,
+ time = 1585768018462L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
- inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic @android.compat.annotation.UnsupportedAppUsage @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> getPresentationSpecs()\npublic void setHostInputToken(android.os.IBinder)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\npublic @android.compat.annotation.UnsupportedAppUsage @android.annotation.NonNull android.view.inputmethod.InlineSuggestionsRequest.Builder addPresentationSpecs(android.view.inline.InlinePresentationSpec)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic @android.compat.annotation.UnsupportedAppUsage @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> getPresentationSpecs()\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\npublic @android.compat.annotation.UnsupportedAppUsage @android.annotation.NonNull android.view.inputmethod.InlineSuggestionsRequest.Builder addPresentationSpecs(android.view.inline.InlinePresentationSpec)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/widget/inline/InlinePresentationSpec.java b/core/java/android/widget/inline/InlinePresentationSpec.java
index 00eb3ce..5635857 100644
--- a/core/java/android/widget/inline/InlinePresentationSpec.java
+++ b/core/java/android/widget/inline/InlinePresentationSpec.java
@@ -23,6 +23,7 @@
import android.util.Size;
import com.android.internal.util.DataClass;
+import com.android.internal.widget.InlinePresentationStyleUtils;
/**
* This class represents the presentation specification by which an inline suggestion
@@ -52,6 +53,10 @@
return Bundle.EMPTY;
}
+ private boolean styleEquals(@NonNull Bundle style) {
+ return InlinePresentationStyleUtils.bundleEquals(mStyle, style);
+ }
+
/** @hide */
@DataClass.Suppress({"setMaxSize", "setMinSize"})
abstract static class BaseBuilder {
@@ -143,7 +148,7 @@
return true
&& java.util.Objects.equals(mMinSize, that.mMinSize)
&& java.util.Objects.equals(mMaxSize, that.mMaxSize)
- && java.util.Objects.equals(mStyle, that.mStyle);
+ && styleEquals(that.mStyle);
}
@Override
@@ -280,10 +285,10 @@
}
@DataClass.Generated(
- time = 1585605466300L,
+ time = 1585768046898L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/widget/inline/InlinePresentationSpec.java",
- inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nprivate final @android.annotation.NonNull android.os.Bundle mStyle\nprivate static @android.annotation.NonNull android.os.Bundle defaultStyle()\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nprivate final @android.annotation.NonNull android.os.Bundle mStyle\nprivate static @android.annotation.NonNull android.os.Bundle defaultStyle()\nprivate boolean styleEquals(android.os.Bundle)\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
new file mode 100644
index 0000000..eee222b
--- /dev/null
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.window;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
+import android.os.RemoteException;
+import android.util.Singleton;
+
+/**
+ * Interface for WindowManager to delegate control of display areas.
+ * @hide
+ */
+@TestApi
+public class DisplayAreaOrganizer extends WindowOrganizer {
+
+ public static final int FEATURE_UNDEFINED = -1;
+ public static final int FEATURE_SYSTEM_FIRST = 0;
+ // The Root display area on a display
+ public static final int FEATURE_ROOT = FEATURE_SYSTEM_FIRST;
+ // Display area hosting the task container.
+ public static final int FEATURE_TASK_CONTAINER = FEATURE_SYSTEM_FIRST + 1;
+ // Display area hosting non-activity window tokens.
+ public static final int FEATURE_WINDOW_TOKENS = FEATURE_SYSTEM_FIRST + 2;
+
+ public static final int FEATURE_SYSTEM_LAST = 10_000;
+
+ // Vendor specific display area definition can start with this value.
+ public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1;
+
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void registerOrganizer(int displayAreaFeature) {
+ try {
+ getController().registerOrganizer(mInterface, displayAreaFeature);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ public void onDisplayAreaAppeared(@NonNull WindowContainerToken displayArea) {}
+
+ public void onDisplayAreaVanished(@NonNull WindowContainerToken displayArea) {}
+
+
+ private final IDisplayAreaOrganizer mInterface = new IDisplayAreaOrganizer.Stub() {
+
+ @Override
+ public void onDisplayAreaAppeared(@NonNull WindowContainerToken displayArea) {
+ DisplayAreaOrganizer.this.onDisplayAreaAppeared(displayArea);
+ }
+
+ @Override
+ public void onDisplayAreaVanished(@NonNull WindowContainerToken displayArea) {
+ DisplayAreaOrganizer.this.onDisplayAreaVanished(displayArea);
+ }
+ };
+
+ private static IDisplayAreaOrganizerController getController() {
+ return IDisplayAreaOrganizerControllerSingleton.get();
+ }
+
+ private static final Singleton<IDisplayAreaOrganizerController>
+ IDisplayAreaOrganizerControllerSingleton =
+ new Singleton<IDisplayAreaOrganizerController>() {
+ @Override
+ protected IDisplayAreaOrganizerController create() {
+ try {
+ return getWindowOrganizerController()
+ .getDisplayAreaOrganizerController();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+ };
+
+}
diff --git a/core/java/android/window/IDisplayAreaOrganizer.aidl b/core/java/android/window/IDisplayAreaOrganizer.aidl
index 1045ab2..9c72e60 100644
--- a/core/java/android/window/IDisplayAreaOrganizer.aidl
+++ b/core/java/android/window/IDisplayAreaOrganizer.aidl
@@ -16,13 +16,13 @@
package android.window;
-import android.window.IWindowContainer;
+import android.window.WindowContainerToken;
/**
* Interface for WindowManager to delegate control of display areas.
* {@hide}
*/
oneway interface IDisplayAreaOrganizer {
- void onDisplayAreaAppeared(in IWindowContainer displayArea);
- void onDisplayAreaVanished(in IWindowContainer displayArea);
+ void onDisplayAreaAppeared(in WindowContainerToken displayArea);
+ void onDisplayAreaVanished(in WindowContainerToken displayArea);
}
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index b038b0f..b4f0162 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -18,7 +18,7 @@
import android.view.SurfaceControl;
import android.app.ActivityManager;
-import android.window.IWindowContainer;
+import android.window.WindowContainerToken;
/**
* Interface for ActivityTaskManager/WindowManager to delegate control of tasks.
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index ba65915..1c03b2f 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -18,7 +18,7 @@
import android.app.ActivityManager;
import android.window.ITaskOrganizer;
-import android.window.IWindowContainer;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
/** @hide */
@@ -40,23 +40,23 @@
ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode);
/** Deletes a persistent root task in WM */
- boolean deleteRootTask(IWindowContainer task);
+ boolean deleteRootTask(in WindowContainerToken task);
/** Gets direct child tasks (ordered from top-to-bottom) */
- List<ActivityManager.RunningTaskInfo> getChildTasks(in IWindowContainer parent,
+ List<ActivityManager.RunningTaskInfo> getChildTasks(in WindowContainerToken parent,
in int[] activityTypes);
/** Gets all root tasks on a display (ordered from top-to-bottom) */
List<ActivityManager.RunningTaskInfo> getRootTasks(int displayId, in int[] activityTypes);
/** Get the root task which contains the current ime target */
- IWindowContainer getImeTarget(int display);
+ WindowContainerToken getImeTarget(int display);
/**
* Set's the root task to launch new tasks into on a display. {@code null} means no launch root
* and thus new tasks just end up directly on the display.
*/
- void setLaunchRoot(int displayId, in IWindowContainer root);
+ void setLaunchRoot(int displayId, in WindowContainerToken root);
/**
* Requests that the given task organizer is notified when back is pressed on the root activity
diff --git a/core/java/android/window/IWindowContainer.aidl b/core/java/android/window/IWindowContainerToken.aidl
similarity index 96%
rename from core/java/android/window/IWindowContainer.aidl
rename to core/java/android/window/IWindowContainerToken.aidl
index f2960f6..57c7abf 100644
--- a/core/java/android/window/IWindowContainer.aidl
+++ b/core/java/android/window/IWindowContainerToken.aidl
@@ -23,7 +23,7 @@
* token.
* @hide
*/
-interface IWindowContainer {
+interface IWindowContainerToken {
/**
* Gets a persistent leash for this container or {@code null}.
diff --git a/core/java/android/window/IWindowContainerTransactionCallback.aidl b/core/java/android/window/IWindowContainerTransactionCallback.aidl
index 0579932..eb07965 100644
--- a/core/java/android/window/IWindowContainerTransactionCallback.aidl
+++ b/core/java/android/window/IWindowContainerTransactionCallback.aidl
@@ -24,5 +24,5 @@
*/
oneway interface IWindowContainerTransactionCallback {
/** Called upon completion of WindowOrganizer#applyTransaction */
- void transactionReady(int id, in SurfaceControl.Transaction t);
+ void onTransactionReady(int id, in SurfaceControl.Transaction t);
}
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/window/TaskEmbedder.java
similarity index 97%
rename from core/java/android/app/TaskEmbedder.java
rename to core/java/android/window/TaskEmbedder.java
index 10c11f2..45ab310 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/window/TaskEmbedder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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,13 +14,19 @@
* limitations under the License.
*/
-package android.app;
+package android.window;
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
+import android.app.ActivityView;
+import android.app.IActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.TaskStackListener;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
new file mode 100644
index 0000000..5098b44
--- /dev/null
+++ b/core/java/android/window/TaskOrganizer.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2020 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.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
+import android.app.ActivityManager;
+import android.os.RemoteException;
+import android.util.Singleton;
+
+import java.util.List;
+
+/**
+ * Interface for ActivityTaskManager/WindowManager to delegate control of tasks.
+ * @hide
+ */
+@TestApi
+public class TaskOrganizer extends WindowOrganizer {
+
+ /**
+ * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
+ * If there was already a TaskOrganizer for this windowing mode it will be evicted
+ * and receive taskVanished callbacks in the process.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void registerOrganizer(int windowingMode) {
+ try {
+ getController().registerTaskOrganizer(mInterface, windowingMode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Unregisters a previously registered task organizer. */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void unregisterOrganizer() {
+ try {
+ getController().unregisterTaskOrganizer(mInterface);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ public void onTaskAppeared(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
+
+ public void onTaskVanished(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
+
+ public void onTaskInfoChanged(@NonNull ActivityManager.RunningTaskInfo info) {}
+
+ public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo info) {}
+
+ /** Creates a persistent root task in WM for a particular windowing-mode. */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ @Nullable
+ public static ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode) {
+ try {
+ return getController().createRootTask(displayId, windowingMode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Deletes a persistent root task in WM */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public static boolean deleteRootTask(@NonNull WindowContainerToken task) {
+ try {
+ return getController().deleteRootTask(task);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Gets direct child tasks (ordered from top-to-bottom) */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ @Nullable
+ public static List<ActivityManager.RunningTaskInfo> getChildTasks(
+ @NonNull WindowContainerToken parent, @NonNull int[] activityTypes) {
+ try {
+ return getController().getChildTasks(parent, activityTypes);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Gets all root tasks on a display (ordered from top-to-bottom) */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ @Nullable
+ public static List<ActivityManager.RunningTaskInfo> getRootTasks(
+ int displayId, @NonNull int[] activityTypes) {
+ try {
+ return getController().getRootTasks(displayId, activityTypes);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Get the root task which contains the current ime target */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ @Nullable
+ public static WindowContainerToken getImeTarget(int display) {
+ try {
+ return getController().getImeTarget(display);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set's the root task to launch new tasks into on a display. {@code null} means no launch
+ * root and thus new tasks just end up directly on the display.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public static void setLaunchRoot(int displayId, @NonNull WindowContainerToken root) {
+ try {
+ getController().setLaunchRoot(displayId, root);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Requests that the given task organizer is notified when back is pressed on the root activity
+ * of one of its controlled tasks.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) {
+ try {
+ getController().setInterceptBackPressedOnTaskRoot(mInterface, interceptBackPressed);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
+
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
+ TaskOrganizer.this.onTaskAppeared(taskInfo);
+ }
+
+ @Override
+ public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ TaskOrganizer.this.onTaskVanished(taskInfo);
+ }
+
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ TaskOrganizer.this.onTaskInfoChanged(info);
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) {
+ TaskOrganizer.this.onBackPressedOnTaskRoot(info);
+ }
+ };
+
+ private static ITaskOrganizerController getController() {
+ return ITaskOrganizerControllerSingleton.get();
+ }
+
+ private static final Singleton<ITaskOrganizerController> ITaskOrganizerControllerSingleton =
+ new Singleton<ITaskOrganizerController>() {
+ @Override
+ protected ITaskOrganizerController create() {
+ try {
+ return getWindowOrganizerController().getTaskOrganizerController();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+ };
+}
diff --git a/core/java/android/app/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
similarity index 79%
rename from core/java/android/app/TaskOrganizerTaskEmbedder.java
rename to core/java/android/window/TaskOrganizerTaskEmbedder.java
index adc0792..2091c93 100644
--- a/core/java/android/app/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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,22 +14,20 @@
* limitations under the License.
*/
-package android.app;
+package android.window;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ActivityView;
+import android.app.TaskStackListener;
import android.content.Context;
import android.graphics.Rect;
-import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceControl;
-import android.window.ITaskOrganizer;
-import android.window.IWindowContainer;
-import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
-import android.window.WindowOrganizer.TaskOrganizer;
/**
* A component which handles embedded display of tasks within another window. The embedded task can
@@ -41,9 +39,9 @@
private static final String TAG = "TaskOrgTaskEmbedder";
private static final boolean DEBUG = false;
- private ITaskOrganizer.Stub mTaskOrganizer;
+ private TaskOrganizer mTaskOrganizer;
private ActivityManager.RunningTaskInfo mTaskInfo;
- private IWindowContainer mTaskToken;
+ private WindowContainerToken mTaskToken;
private SurfaceControl mTaskLeash;
private boolean mPendingNotifyBoundsChanged;
@@ -79,16 +77,11 @@
}
// Register the task organizer
mTaskOrganizer = new TaskOrganizerImpl();
- try {
- // TODO(wm-shell): This currently prevents other organizers from controlling MULT_WINDOW
- // windowing mode tasks. Plan is to migrate this to a wm-shell front-end when that
- // infrastructure is ready.
- TaskOrganizer.registerOrganizer(mTaskOrganizer, WINDOWING_MODE_MULTI_WINDOW);
- TaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskOrganizer, true);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to initialize TaskEmbedder", e);
- return false;
- }
+ // TODO(wm-shell): This currently prevents other organizers from controlling MULT_WINDOW
+ // windowing mode tasks. Plan is to migrate this to a wm-shell front-end when that
+ // infrastructure is ready.
+ mTaskOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+ mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);
return true;
}
@@ -100,11 +93,7 @@
if (!isInitialized()) {
return false;
}
- try {
- TaskOrganizer.unregisterOrganizer(mTaskOrganizer);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to remove task");
- }
+ mTaskOrganizer.unregisterOrganizer();
resetTaskInfo();
return true;
}
@@ -125,11 +114,7 @@
}
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setHidden(mTaskToken, false /* hidden */);
- try {
- WindowOrganizer.applyTransaction(wct);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to unset hidden in transaction");
- }
+ WindowOrganizer.applyTransaction(wct);
// TODO(b/151449487): Only call callback once we enable synchronization
if (mListener != null) {
mListener.onTaskVisibilityChanged(getTaskId(), true);
@@ -152,11 +137,7 @@
}
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setHidden(mTaskToken, true /* hidden */);
- try {
- WindowOrganizer.applyTransaction(wct);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to set hidden in transaction");
- }
+ WindowOrganizer.applyTransaction(wct);
// TODO(b/151449487): Only call callback once we enable synchronization
if (mListener != null) {
mListener.onTaskVisibilityChanged(getTaskId(), false);
@@ -186,12 +167,8 @@
WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setBounds(mTaskToken, screenBounds);
- try {
- // TODO(b/151449487): Enable synchronization
- WindowOrganizer.applyTransaction(wct);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to set bounds in transaction");
- }
+ // TODO(b/151449487): Enable synchronization
+ WindowOrganizer.applyTransaction(wct);
}
/**
@@ -253,8 +230,7 @@
private class TaskStackListenerImpl extends TaskStackListener {
@Override
- public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo)
- throws RemoteException {
+ public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) {
if (!isInitialized()) {
return;
}
@@ -266,10 +242,9 @@
}
}
- private class TaskOrganizerImpl extends ITaskOrganizer.Stub {
+ private class TaskOrganizerImpl extends TaskOrganizer {
@Override
- public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo)
- throws RemoteException {
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) {
if (DEBUG) {
log("taskAppeared: " + taskInfo.taskId);
}
@@ -293,8 +268,7 @@
}
@Override
- public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo)
- throws RemoteException {
+ public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
if (DEBUG) {
log("taskVanished: " + taskInfo.taskId);
}
@@ -309,14 +283,7 @@
}
@Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo)
- throws RemoteException {
- // Do nothing
- }
-
- @Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo)
- throws RemoteException {
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
if (mListener != null) {
mListener.onBackPressedOnTaskRoot(taskInfo.taskId);
}
diff --git a/core/java/android/app/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
similarity index 97%
rename from core/java/android/app/VirtualDisplayTaskEmbedder.java
rename to core/java/android/window/VirtualDisplayTaskEmbedder.java
index 7ad8f22..1afbfeb 100644
--- a/core/java/android/app/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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,7 +14,7 @@
* limitations under the License.
*/
-package android.app;
+package android.window;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
@@ -23,6 +23,11 @@
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
+import android.app.ActivityView;
+import android.app.TaskStackListener;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Insets;
@@ -72,7 +77,7 @@
* @param singleTaskInstance whether to apply a single-task constraint to this container,
* only applicable if virtual displays are used
*/
- VirtualDisplayTaskEmbedder(Context context, VirtualDisplayTaskEmbedder.Host host,
+ public VirtualDisplayTaskEmbedder(Context context, VirtualDisplayTaskEmbedder.Host host,
boolean singleTaskInstance) {
super(context, host);
mSingleTaskInstance = singleTaskInstance;
@@ -243,7 +248,6 @@
options = super.prepareActivityOptions(options);
options.setLaunchDisplayId(getDisplayId());
options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- options.setTaskAlwaysOnTop(true);
return options;
}
diff --git a/core/java/android/window/IWindowContainer.aidl b/core/java/android/window/WindowContainerToken.aidl
similarity index 62%
copy from core/java/android/window/IWindowContainer.aidl
copy to core/java/android/window/WindowContainerToken.aidl
index f2960f6..f22786b 100644
--- a/core/java/android/window/IWindowContainer.aidl
+++ b/core/java/android/window/WindowContainerToken.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -16,17 +16,4 @@
package android.window;
-import android.view.SurfaceControl;
-
-/**
- * Interface for a window container to communicate with the window manager. This also acts as a
- * token.
- * @hide
- */
-interface IWindowContainer {
-
- /**
- * Gets a persistent leash for this container or {@code null}.
- */
- SurfaceControl getLeash();
-}
+parcelable WindowContainerToken;
diff --git a/core/java/android/window/WindowContainerToken.java b/core/java/android/window/WindowContainerToken.java
new file mode 100644
index 0000000..dde98da
--- /dev/null
+++ b/core/java/android/window/WindowContainerToken.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 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.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.view.SurfaceControl;
+import android.window.IWindowContainerToken;
+
+/**
+ * Interface for a window container to communicate with the window manager. This also acts as a
+ * token.
+ * @hide
+ */
+@TestApi
+public final class WindowContainerToken implements Parcelable {
+
+ private final IWindowContainerToken mRealToken;
+
+ /** @hide */
+ public WindowContainerToken(IWindowContainerToken realToken) {
+ mRealToken = realToken;
+ }
+
+ private WindowContainerToken(Parcel in) {
+ mRealToken = IWindowContainerToken.Stub.asInterface(in.readStrongBinder());
+ }
+
+ @Nullable
+ public SurfaceControl getLeash() {
+ try {
+ return mRealToken.getLeash();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public IBinder asBinder() {
+ return mRealToken.asBinder();
+ }
+
+ @Override
+ /** @hide */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStrongBinder(mRealToken.asBinder());
+ }
+
+ @NonNull
+ public static final Creator<WindowContainerToken> CREATOR =
+ new Creator<WindowContainerToken>() {
+ @Override
+ public WindowContainerToken createFromParcel(Parcel in) {
+ return new WindowContainerToken(in);
+ }
+
+ @Override
+ public WindowContainerToken[] newArray(int size) {
+ return new WindowContainerToken[size];
+ }
+ };
+
+ @Override
+ /** @hide */
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 483dec6..231e024 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -26,7 +27,6 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
-import android.window.IWindowContainer;
import android.view.SurfaceControl;
import java.util.ArrayList;
@@ -39,7 +39,8 @@
*
* @hide
*/
-public class WindowContainerTransaction implements Parcelable {
+@TestApi
+public final class WindowContainerTransaction implements Parcelable {
private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
// Flat list because re-order operations are order-dependent
@@ -47,7 +48,7 @@
public WindowContainerTransaction() {}
- protected WindowContainerTransaction(Parcel in) {
+ private WindowContainerTransaction(Parcel in) {
in.readMap(mChanges, null /* loader */);
in.readList(mHierarchyOps, null /* loader */);
}
@@ -64,7 +65,9 @@
/**
* Resize a container.
*/
- public WindowContainerTransaction setBounds(IWindowContainer container, Rect bounds) {
+ @NonNull
+ public WindowContainerTransaction setBounds(
+ @NonNull WindowContainerToken container,@NonNull Rect bounds) {
Change chg = getOrCreateChange(container.asBinder());
chg.mConfiguration.windowConfiguration.setBounds(bounds);
chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
@@ -77,7 +80,9 @@
* app's DisplayInfo. It is derived by subtracting the overlapping portion of the navbar from
* the full bounds.
*/
- public WindowContainerTransaction setAppBounds(IWindowContainer container, Rect appBounds) {
+ @NonNull
+ public WindowContainerTransaction setAppBounds(
+ @NonNull WindowContainerToken container,@NonNull Rect appBounds) {
Change chg = getOrCreateChange(container.asBinder());
chg.mConfiguration.windowConfiguration.setAppBounds(appBounds);
chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
@@ -91,7 +96,9 @@
* derived by subtracting the overlapping portions of both the statusbar and the navbar from
* the full bounds.
*/
- public WindowContainerTransaction setScreenSizeDp(IWindowContainer container, int w, int h) {
+ @NonNull
+ public WindowContainerTransaction setScreenSizeDp(
+ @NonNull WindowContainerToken container, int w, int h) {
Change chg = getOrCreateChange(container.asBinder());
chg.mConfiguration.screenWidthDp = w;
chg.mConfiguration.screenHeightDp = h;
@@ -100,11 +107,12 @@
}
/**
- * Notify activies within the hiearchy of a container that they have entered picture-in-picture
+ * Notify activities within the hierarchy of a container that they have entered picture-in-picture
* mode with the given bounds.
*/
- public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container,
- Rect bounds) {
+ @NonNull
+ public WindowContainerTransaction scheduleFinishEnterPip(
+ @NonNull WindowContainerToken container,@NonNull Rect bounds) {
Change chg = getOrCreateChange(container.asBinder());
chg.mPinnedBounds = new Rect(bounds);
chg.mChangeMask |= Change.CHANGE_PIP_CALLBACK;
@@ -123,8 +131,9 @@
* that you can call this, apply the WindowContainer transaction, and then later call
* dismissPip() to achieve synchronization.
*/
- public WindowContainerTransaction setBoundsChangeTransaction(IWindowContainer container,
- SurfaceControl.Transaction t) {
+ @NonNull
+ public WindowContainerTransaction setBoundsChangeTransaction(
+ @NonNull WindowContainerToken container,@NonNull SurfaceControl.Transaction t) {
Change chg = getOrCreateChange(container.asBinder());
chg.mBoundsChangeTransaction = t;
chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION;
@@ -139,8 +148,9 @@
*
* TODO(b/134365562): Can be removed once TaskOrg drives full-screen
*/
- public WindowContainerTransaction setActivityWindowingMode(IWindowContainer container,
- int windowingMode) {
+ @NonNull
+ public WindowContainerTransaction setActivityWindowingMode(
+ @NonNull WindowContainerToken container, int windowingMode) {
Change chg = getOrCreateChange(container.asBinder());
chg.mActivityWindowingMode = windowingMode;
return this;
@@ -149,8 +159,9 @@
/**
* Sets the windowing mode of the given container.
*/
- public WindowContainerTransaction setWindowingMode(IWindowContainer container,
- int windowingMode) {
+ @NonNull
+ public WindowContainerTransaction setWindowingMode(
+ @NonNull WindowContainerToken container, int windowingMode) {
Change chg = getOrCreateChange(container.asBinder());
chg.mWindowingMode = windowingMode;
return this;
@@ -161,7 +172,9 @@
* child can be focused; however, when {@code true}, it is still possible for children to be
* non-focusable due to WM policy.
*/
- public WindowContainerTransaction setFocusable(IWindowContainer container, boolean focusable) {
+ @NonNull
+ public WindowContainerTransaction setFocusable(
+ @NonNull WindowContainerToken container, boolean focusable) {
Change chg = getOrCreateChange(container.asBinder());
chg.mFocusable = focusable;
chg.mChangeMask |= Change.CHANGE_FOCUSABLE;
@@ -173,7 +186,9 @@
* visibility of the container applies, but when {@code true} the container will be forced
* to be hidden.
*/
- public WindowContainerTransaction setHidden(IWindowContainer container, boolean hidden) {
+ @NonNull
+ public WindowContainerTransaction setHidden(
+ @NonNull WindowContainerToken container, boolean hidden) {
Change chg = getOrCreateChange(container.asBinder());
chg.mHidden = hidden;
chg.mChangeMask |= Change.CHANGE_HIDDEN;
@@ -183,8 +198,9 @@
/**
* Set the smallestScreenWidth of a container.
*/
- public WindowContainerTransaction setSmallestScreenWidthDp(IWindowContainer container,
- int widthDp) {
+ @NonNull
+ public WindowContainerTransaction setSmallestScreenWidthDp(
+ @NonNull WindowContainerToken container, int widthDp) {
Change cfg = getOrCreateChange(container.asBinder());
cfg.mConfiguration.smallestScreenWidthDp = widthDp;
cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
@@ -198,8 +214,9 @@
* @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
* the bottom.
*/
- public WindowContainerTransaction reparent(@NonNull IWindowContainer child,
- @Nullable IWindowContainer parent, boolean onTop) {
+ @NonNull
+ public WindowContainerTransaction reparent(@NonNull WindowContainerToken child,
+ @Nullable WindowContainerToken parent, boolean onTop) {
mHierarchyOps.add(new HierarchyOp(child.asBinder(),
parent == null ? null : parent.asBinder(), onTop));
return this;
@@ -211,36 +228,43 @@
* @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to
* the bottom.
*/
- public WindowContainerTransaction reorder(@NonNull IWindowContainer child, boolean onTop) {
+ @NonNull
+ public WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop) {
mHierarchyOps.add(new HierarchyOp(child.asBinder(), onTop));
return this;
}
+ /** @hide */
public Map<IBinder, Change> getChanges() {
return mChanges;
}
+ /** @hide */
public List<HierarchyOp> getHierarchyOps() {
return mHierarchyOps;
}
@Override
+ @NonNull
public String toString() {
return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps
+ " }";
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ /** @hide */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeMap(mChanges);
dest.writeList(mHierarchyOps);
}
@Override
+ /** @hide */
public int describeContents() {
return 0;
}
+ @NonNull
public static final Creator<WindowContainerTransaction> CREATOR =
new Creator<WindowContainerTransaction>() {
@Override
@@ -256,7 +280,6 @@
/**
* Holds changes on a single WindowContainer including Configuration changes.
- *
* @hide
*/
public static class Change implements Parcelable {
@@ -430,6 +453,7 @@
/**
* Holds information about a reparent/reorder operation in the hierarchy. This is separate from
* Changes because they must be executed in the same order that they are added.
+ * @hide
*/
public static class HierarchyOp implements Parcelable {
private final IBinder mContainer;
diff --git a/core/java/android/window/WindowContainerTransactionCallback.java b/core/java/android/window/WindowContainerTransactionCallback.java
new file mode 100644
index 0000000..67cb1e7
--- /dev/null
+++ b/core/java/android/window/WindowContainerTransactionCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.window;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.view.SurfaceControl;
+
+
+/**
+ * See WindowOrganizer#applyTransaction.
+ * {@hide}
+ */
+@TestApi
+public abstract class WindowContainerTransactionCallback {
+
+ public abstract void onTransactionReady(int id, @NonNull SurfaceControl.Transaction t);
+
+ /** @hide */
+ final IWindowContainerTransactionCallback mInterface =
+ new IWindowContainerTransactionCallback.Stub() {
+ @Override
+ public void onTransactionReady(int id, SurfaceControl.Transaction t) {
+ WindowContainerTransactionCallback.this.onTransactionReady(id, t);
+ }
+ };
+}
diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java
index 5590e72..4578271 100644
--- a/core/java/android/window/WindowOrganizer.java
+++ b/core/java/android/window/WindowOrganizer.java
@@ -16,29 +16,32 @@
package android.window;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.app.ActivityManager;
+import android.annotation.TestApi;
import android.app.ActivityTaskManager;
import android.os.RemoteException;
import android.util.Singleton;
-import java.util.List;
-
/**
- * Class for organizing specific types of windows like Tasks and DisplayAreas
+ * Base class for organizing specific types of windows like Tasks and DisplayAreas
*
* @hide
*/
+@TestApi
public class WindowOrganizer {
/**
* Apply multiple WindowContainer operations at once.
* @param t The transaction to apply.
- * @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static void applyTransaction(WindowContainerTransaction t) throws RemoteException {
- getWindowOrganizerController().applyTransaction(t);
+ public static void applyTransaction(@NonNull WindowContainerTransaction t) {
+ try {
+ getWindowOrganizerController().applyTransaction(t);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -49,17 +52,19 @@
* WindowContainer transaction will be passed to this callback when ready.
* @return An ID for the sync operation which will later be passed to transactionReady callback.
* This lets the caller differentiate overlapping sync operations.
- * @hide
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static int applySyncTransaction(WindowContainerTransaction t,
- IWindowContainerTransactionCallback callback) throws RemoteException {
- return getWindowOrganizerController().applySyncTransaction(t, callback);
+ public int applySyncTransaction(@NonNull WindowContainerTransaction t,
+ @NonNull WindowContainerTransactionCallback callback) {
+ try {
+ return getWindowOrganizerController().applySyncTransaction(t, callback.mInterface);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
- /** @hide */
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- private static IWindowOrganizerController getWindowOrganizerController() {
+ static IWindowOrganizerController getWindowOrganizerController() {
return IWindowOrganizerControllerSingleton.get();
}
@@ -74,138 +79,4 @@
}
}
};
-
- public static class TaskOrganizer {
-
- /**
- * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
- * If there was already a TaskOrganizer for this windowing mode it will be evicted
- * and receive taskVanished callbacks in the process.
- */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static void registerOrganizer(ITaskOrganizer organizer, int windowingMode)
- throws RemoteException {
- getController().registerTaskOrganizer(organizer, windowingMode);
- }
-
- /** Unregisters a previously registered task organizer. */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static void unregisterOrganizer(ITaskOrganizer organizer) throws RemoteException {
- getController().unregisterTaskOrganizer(organizer);
- }
-
- /** Creates a persistent root task in WM for a particular windowing-mode. */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static ActivityManager.RunningTaskInfo createRootTask(
- int displayId, int windowingMode) throws RemoteException {
- return getController().createRootTask(displayId, windowingMode);
- }
-
- /** Deletes a persistent root task in WM */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static boolean deleteRootTask(IWindowContainer task) throws RemoteException {
- return getController().deleteRootTask(task);
- }
-
- /** Gets direct child tasks (ordered from top-to-bottom) */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static List<ActivityManager.RunningTaskInfo> getChildTasks(IWindowContainer parent,
- int[] activityTypes) throws RemoteException {
- return getController().getChildTasks(parent, activityTypes);
- }
-
- /** Gets all root tasks on a display (ordered from top-to-bottom) */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static List<ActivityManager.RunningTaskInfo> getRootTasks(
- int displayId, int[] activityTypes) throws RemoteException {
- return getController().getRootTasks(displayId, activityTypes);
- }
-
- /** Get the root task which contains the current ime target */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static IWindowContainer getImeTarget(int display) throws RemoteException {
- return getController().getImeTarget(display);
- }
-
- /**
- * Set's the root task to launch new tasks into on a display. {@code null} means no launch
- * root and thus new tasks just end up directly on the display.
- */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static void setLaunchRoot(int displayId, IWindowContainer root)
- throws RemoteException {
- getController().setLaunchRoot(displayId, root);
- }
-
- /**
- * Requests that the given task organizer is notified when back is pressed on the root
- * activity of one of its controlled tasks.
- */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer,
- boolean interceptBackPressed) throws RemoteException {
- getController().setInterceptBackPressedOnTaskRoot(organizer, interceptBackPressed);
- }
-
- private static ITaskOrganizerController getController() {
- return ITaskOrganizerControllerSingleton.get();
- }
-
- private static final Singleton<ITaskOrganizerController> ITaskOrganizerControllerSingleton =
- new Singleton<ITaskOrganizerController>() {
- @Override
- protected ITaskOrganizerController create() {
- try {
- return getWindowOrganizerController().getTaskOrganizerController();
- } catch (RemoteException e) {
- return null;
- }
- }
- };
- }
-
- /** Class for organizing display areas. */
- public static class DisplayAreaOrganizer {
-
- public static final int FEATURE_UNDEFINED = -1;
- public static final int FEATURE_SYSTEM_FIRST = 0;
- // The Root display area on a display
- public static final int FEATURE_ROOT = FEATURE_SYSTEM_FIRST;
- // Display area hosting the task container.
- public static final int FEATURE_TASK_CONTAINER = FEATURE_SYSTEM_FIRST + 1;
- // Display area hosting non-activity window tokens.
- public static final int FEATURE_WINDOW_TOKENS = FEATURE_SYSTEM_FIRST + 2;
-
- public static final int FEATURE_SYSTEM_LAST = 10_000;
-
- // Vendor specific display area definition can start with this value.
- public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1;
-
- /** @hide */
- @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public static void registerOrganizer(
- IDisplayAreaOrganizer organizer, int displayAreaFeature) throws RemoteException {
- getController().registerOrganizer(organizer, displayAreaFeature);
- }
-
- /** @hide */
- private static IDisplayAreaOrganizerController getController() {
- return IDisplayAreaOrganizerControllerSingleton.get();
- }
-
- private static final Singleton<IDisplayAreaOrganizerController>
- IDisplayAreaOrganizerControllerSingleton =
- new Singleton<IDisplayAreaOrganizerController>() {
- @Override
- protected IDisplayAreaOrganizerController create() {
- try {
- return getWindowOrganizerController()
- .getDisplayAreaOrganizerController();
- } catch (RemoteException e) {
- return null;
- }
- }
- };
-
- }
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 1336ec4..ab68c44 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -45,6 +45,7 @@
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.RemotableViewMethod;
+import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -62,6 +63,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.function.Consumer;
import java.util.regex.Pattern;
@@ -151,6 +153,10 @@
private int mFacePileProtectionWidth;
private int mFacePileProtectionWidthExpanded;
private boolean mImportantConversation;
+ private TextView mUnreadBadge;
+ private ViewGroup mAppOps;
+ private Rect mAppOpsTouchRect = new Rect();
+ private float mMinTouchSize;
public ConversationLayout(@NonNull Context context) {
super(context);
@@ -189,6 +195,8 @@
mConversationIcon = findViewById(R.id.conversation_icon);
mConversationIconContainer = findViewById(R.id.conversation_icon_container);
mIcon = findViewById(R.id.icon);
+ mAppOps = findViewById(com.android.internal.R.id.app_ops);
+ mMinTouchSize = 48 * getResources().getDisplayMetrics().density;
mImportanceRingView = findViewById(R.id.conversation_icon_badge_ring);
mConversationIconBadge = findViewById(R.id.conversation_icon_badge);
mConversationIconBadgeBg = findViewById(R.id.conversation_icon_badge_bg);
@@ -277,6 +285,7 @@
mAppName.setOnVisibilityChangedListener((visibility) -> {
onAppNameVisibilityChanged();
});
+ mUnreadBadge = findViewById(R.id.conversation_unread_count);
mConversationContentStart = getResources().getDimensionPixelSize(
R.dimen.conversation_content_start);
mInternalButtonPadding
@@ -354,7 +363,6 @@
// mUser now set (would be nice to avoid the side effect but WHATEVER)
setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
-
// Append remote input history to newMessages (again, side effect is lame but WHATEVS)
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
@@ -362,9 +370,11 @@
boolean showSpinner =
extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
-
// bind it, baby
bind(newMessages, newHistoricMessages, showSpinner);
+
+ int unreadCount = extras.getInt(Notification.EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
+ setUnreadCount(unreadCount);
}
@Override
@@ -372,6 +382,18 @@
mImageResolver = resolver;
}
+ /** @hide */
+ public void setUnreadCount(int unreadCount) {
+ mUnreadBadge.setVisibility(mIsCollapsed && unreadCount > 1 ? VISIBLE : GONE);
+ CharSequence text = unreadCount >= 100
+ ? getResources().getString(R.string.unread_convo_overflow, 99)
+ : String.format(Locale.getDefault(), "%d", unreadCount);
+ mUnreadBadge.setText(text);
+ mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor));
+ boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f;
+ mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE);
+ }
+
private void addRemoteInputHistoryToMessages(
List<Notification.MessagingStyle.Message> newMessages,
RemoteInputHistoryItem[] remoteInputHistory) {
@@ -855,6 +877,7 @@
@RemotableViewMethod
public void setSenderTextColor(int color) {
mSenderTextColor = color;
+ mConversationText.setTextColor(color);
}
/**
@@ -1055,6 +1078,47 @@
}
});
}
+ if (mAppOps.getWidth() > 0) {
+
+ // Let's increase the touch size of the app ops view if it's here
+ mAppOpsTouchRect.set(
+ mAppOps.getLeft(),
+ mAppOps.getTop(),
+ mAppOps.getRight(),
+ mAppOps.getBottom());
+ for (int i = 0; i < mAppOps.getChildCount(); i++) {
+ View child = mAppOps.getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+ // Make sure each child has at least a minTouchSize touch target around it
+ float childTouchLeft = child.getLeft() + child.getWidth() / 2.0f
+ - mMinTouchSize / 2.0f;
+ float childTouchRight = childTouchLeft + mMinTouchSize;
+ mAppOpsTouchRect.left = (int) Math.min(mAppOpsTouchRect.left,
+ mAppOps.getLeft() + childTouchLeft);
+ mAppOpsTouchRect.right = (int) Math.max(mAppOpsTouchRect.right,
+ mAppOps.getLeft() + childTouchRight);
+ }
+
+ // Increase the height
+ int heightIncrease = 0;
+ if (mAppOpsTouchRect.height() < mMinTouchSize) {
+ heightIncrease = (int) Math.ceil((mMinTouchSize - mAppOpsTouchRect.height())
+ / 2.0f);
+ }
+ mAppOpsTouchRect.inset(0, -heightIncrease);
+
+ // Let's adjust the hitrect since app ops isn't a direct child
+ ViewGroup viewGroup = (ViewGroup) mAppOps.getParent();
+ while (viewGroup != this) {
+ mAppOpsTouchRect.offset(viewGroup.getLeft(), viewGroup.getTop());
+ viewGroup = (ViewGroup) viewGroup.getParent();
+ }
+ //
+ // Extend the size of the app opps to be at least 48dp
+ setTouchDelegate(new TouchDelegate(mAppOpsTouchRect, mAppOps));
+ }
}
public MessagingLinearLayout getMessagingLinearLayout() {
diff --git a/core/java/com/android/internal/widget/InlinePresentationStyleUtils.java b/core/java/com/android/internal/widget/InlinePresentationStyleUtils.java
new file mode 100644
index 0000000..264c8bd
--- /dev/null
+++ b/core/java/com/android/internal/widget/InlinePresentationStyleUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 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.NonNull;
+import android.os.Bundle;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Utility methods relating to inline presentation UI.
+ */
+public final class InlinePresentationStyleUtils {
+
+ /**
+ * Returns true if the two bundles are deeply equal.
+ *
+ * Each input bundle may represent a UI style in the
+ * {@link android.widget.inline.InlinePresentationSpec} or the extra
+ * request info in the {@link android.view.inputmethod.InlineSuggestionsRequest}
+ *
+ * Note: this method should not be called in the framework process for security reasons.
+ */
+ public static boolean bundleEquals(@NonNull Bundle bundle1, @NonNull Bundle bundle2) {
+ if (bundle1 == bundle2) {
+ return true;
+ }
+ if (bundle1 == null || bundle2 == null) {
+ return false;
+ }
+ if (bundle1.size() != bundle2.size()) {
+ return false;
+ }
+ Set<String> keys = bundle1.keySet();
+ for (String key : keys) {
+ Object value1 = bundle1.get(key);
+ Object value2 = bundle2.get(key);
+ if (value1 instanceof Bundle && value2 instanceof Bundle
+ && !bundleEquals((Bundle) value1, (Bundle) value2)) {
+ return false;
+ } else if (!Objects.equals(value1, value2)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Private ctor to avoid constructing the class.
+ */
+ private InlinePresentationStyleUtils() {
+ }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index eae6145..451363f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3788,10 +3788,9 @@
android:protectionLevel="signature|installer" />
<!-- @SystemApi Allows an application to manage the holders of a role.
- @hide
- STOPSHIP b/145526313: Remove wellbeing protection flag from MANAGE_ROLE_HOLDERS. -->
+ @hide -->
<permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
- android:protectionLevel="signature|installer|wellbeing" />
+ android:protectionLevel="signature|installer" />
<!-- @SystemApi Allows an application to observe role holder changes.
@hide -->
@@ -4713,12 +4712,6 @@
<permission android:name="android.permission.MANAGE_SOUND_TRIGGER"
android:protectionLevel="signature|privileged" />
- <!-- Allows preempting sound trigger recognitions for the sake of capturing audio on
- implementations which do not support running both concurrently.
- @hide -->
- <permission android:name="android.permission.PREEMPT_SOUND_TRIGGER"
- android:protectionLevel="signature|privileged" />
-
<!-- Must be required by system/priv apps implementing sound trigger detection services
@hide
@SystemApi -->
diff --git a/core/res/res/drawable/conversation_unread_bg.xml b/core/res/res/drawable/conversation_unread_bg.xml
new file mode 100644
index 0000000..d3e00cf
--- /dev/null
+++ b/core/res/res/drawable/conversation_unread_bg.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="20sp" />
+ <solid android:color="@android:color/white" />
+</shape>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 46d3d13..b9ca292 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -136,6 +136,7 @@
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
android:textSize="16sp"
android:singleLine="true"
+ android:layout_weight="1"
/>
<TextView
@@ -166,6 +167,18 @@
/>
<ImageView
+ android:id="@+id/alerted_icon"
+ android:layout_width="@dimen/notification_alerted_size"
+ android:layout_height="@dimen/notification_alerted_size"
+ android:layout_gravity="center"
+ android:layout_marginStart="4dp"
+ android:paddingTop="2dp"
+ android:scaleType="fitCenter"
+ android:visibility="gone"
+ android:contentDescription="@string/notification_alerted_content_description"
+ android:src="@drawable/ic_notifications_alerted"/>
+
+ <ImageView
android:id="@+id/profile_badge"
android:layout_width="@dimen/notification_badge_size"
android:layout_height="@dimen/notification_badge_size"
@@ -176,6 +189,44 @@
android:visibility="gone"
android:contentDescription="@string/notification_work_profile_content_description"
/>
+ <LinearLayout
+ android:id="@+id/app_ops"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingTop="3dp"
+ android:layout_marginStart="2dp"
+ android:orientation="horizontal" >
+ <ImageButton
+ android:layout_marginStart="4dp"
+ android:id="@+id/camera"
+ android:layout_width="?attr/notificationHeaderIconSize"
+ android:layout_height="?attr/notificationHeaderIconSize"
+ android:src="@drawable/ic_camera"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:visibility="gone"
+ android:contentDescription="@string/notification_appops_camera_active"
+ />
+ <ImageButton
+ android:id="@+id/mic"
+ android:layout_width="?attr/notificationHeaderIconSize"
+ android:layout_height="?attr/notificationHeaderIconSize"
+ android:src="@drawable/ic_mic"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:layout_marginStart="4dp"
+ android:visibility="gone"
+ android:contentDescription="@string/notification_appops_microphone_active"
+ />
+ <ImageButton
+ android:id="@+id/overlay"
+ android:layout_width="?attr/notificationHeaderIconSize"
+ android:layout_height="?attr/notificationHeaderIconSize"
+ android:src="@drawable/ic_alert_window_layer"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:layout_marginStart="4dp"
+ android:visibility="gone"
+ android:contentDescription="@string/notification_appops_overlay_active"
+ />
+ </LinearLayout>
</LinearLayout>
<!-- App Name -->
@@ -199,10 +250,8 @@
android:clipChildren="false"
/>
</com.android.internal.widget.RemeasuringLinearLayout>
- <!-- Unread Count -->
- <!-- <TextView /> -->
- <!-- This is where the expand button will be placed when collapsed-->
+ <!-- This is where the expand button container will be placed when collapsed-->
</com.android.internal.widget.RemeasuringLinearLayout>
<include layout="@layout/notification_template_smart_reply_container"
@@ -238,6 +287,21 @@
android:clipToPadding="false"
android:clipChildren="false"
/>
+ <!-- Unread Count -->
+ <TextView
+ android:id="@+id/conversation_unread_count"
+ android:layout_width="33sp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="11dp"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:padding="2dp"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
+ android:textColor="#FFFFFF"
+ android:textSize="12sp"
+ android:background="@drawable/conversation_unread_bg"
+ />
<com.android.internal.widget.NotificationExpandButton
android:id="@+id/expand_button"
android:layout_width="@dimen/notification_header_expand_icon_size"
@@ -246,6 +310,6 @@
android:drawable="@drawable/ic_expand_notification"
android:clickable="false"
android:importantForAccessibility="no"
- />
+ />
</LinearLayout>
</com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4c4b7e6..b1bba53 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1910,6 +1910,9 @@
<!-- The name of the package that will hold the system gallery role. -->
<string name="config_systemGallery" translatable="false">com.android.gallery</string>
+ <!-- The name of the package that will be allowed to change its components' label/icon. -->
+ <string name="config_overrideComponentUiPackage" translatable="false"></string>
+
<!-- Enable/disable default bluetooth profiles:
HSP_AG, ObexObjectPush, Audio, NAP -->
<bool name="config_bluetooth_default_profiles">true</bool>
@@ -4418,7 +4421,7 @@
<string name="config_customSessionPolicyProvider"></string>
<!-- The max scale for the wallpaper when it's zoomed in -->
- <item name="config_wallpaperMaxScale" format="float" type="dimen">1.15</item>
+ <item name="config_wallpaperMaxScale" format="float" type="dimen">1.10</item>
<!-- Package name that will receive an explicit manifest broadcast for
android.os.action.POWER_SAVE_MODE_CHANGED. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e2e65dd..c9c498e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5442,6 +5442,9 @@
<!-- Conversation Title fallback if the there is no name provided in a group chat conversation [CHAR LIMIT=40]-->
<string name="conversation_title_fallback_group_chat">Group Conversation</string>
+ <!-- Number of unread messages displayed on a conversation notification, when greater-than-or-equal-to 100 [CHAR LIMIT=3]-->
+ <string name="unread_convo_overflow"><xliff:g id="max_unread_count" example="99">%1$d</xliff:g>+</string>
+
<!-- ResolverActivity - profile tabs -->
<!-- Label of a tab on a screen. A user can tap this tap to switch to the 'Personal' view (that shows their personal content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
<string name="resolver_personal_tab">Personal</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0fea372..ec80582 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3898,6 +3898,8 @@
<java-symbol type="dimen" name="button_padding_horizontal_material" />
<java-symbol type="dimen" name="button_inset_horizontal_material" />
<java-symbol type="layout" name="conversation_face_pile_layout" />
+ <java-symbol type="id" name="conversation_unread_count" />
+ <java-symbol type="string" name="unread_convo_overflow" />
<!-- Intent resolver and share sheet -->
<java-symbol type="string" name="resolver_personal_tab" />
@@ -3959,4 +3961,6 @@
<!-- Set to true to make assistant show in front of the dream/screensaver. -->
<java-symbol type="bool" name="config_assistantOnTopOfDream"/>
+
+ <java-symbol type="string" name="config_overrideComponentUiPackage" />
</resources>
diff --git a/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt b/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt
new file mode 100644
index 0000000..d45fee9
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/parsing/result/ParseInputAndResultTest.kt
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2020 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.content.pm.parsing.result
+
+import android.content.pm.PackageManager
+import android.os.Build
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assume.assumeFalse
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Test
+import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import java.io.IOException
+
+class ParseInputAndResultTest {
+
+ companion object {
+
+ private const val TEST_PACKAGE = "com.android.test"
+
+ private const val ENABLED_ERROR = 11L
+ private const val DISABLED_ERROR = 22L
+
+ @JvmStatic
+ @BeforeClass
+ fun assumeNotDebug() {
+ // None of these tests consider cases where debugging logic is enabled
+ assumeFalse(ParseTypeImpl.DEBUG_FILL_STACK_TRACE)
+ assumeFalse(ParseTypeImpl.DEBUG_LOG_ON_ERROR)
+ assumeFalse(ParseTypeImpl.DEBUG_THROW_ALL_ERRORS)
+ }
+ }
+
+ private lateinit var mockCallback: ParseInput.Callback
+ private lateinit var input: ParseInput
+
+ @Before
+ fun createInput() {
+ // Use an open class instead off a lambda so it can be spied
+ open class TestCallback : ParseInput.Callback {
+ override fun isChangeEnabled(changeId: Long, pkgName: String, targetSdk: Int): Boolean {
+ return when (changeId) {
+ ENABLED_ERROR -> targetSdk > Build.VERSION_CODES.Q
+ DISABLED_ERROR -> false
+ else -> throw IllegalStateException("changeId $changeId is not mocked for test")
+ }
+ }
+ }
+
+ mockCallback = spy(TestCallback())
+ input = ParseTypeImpl(mockCallback)
+ }
+
+ @Test
+ fun errorCode() {
+ val errorCode = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE
+ val result = input.error<Any?>(errorCode)
+ assertError(result)
+ assertThat(result.errorCode).isEqualTo(errorCode)
+ assertThat(result.errorMessage).isNull()
+ assertThat(result.exception).isNull()
+ }
+
+ @Test
+ fun errorMessage() {
+ val errorMessage = "Test error"
+ val result = input.error<Any?>(errorMessage)
+ assertError(result)
+ assertThat(result.errorCode).isNotEqualTo(PackageManager.INSTALL_SUCCEEDED)
+ assertThat(result.errorMessage).isEqualTo(errorMessage)
+ assertThat(result.exception).isNull()
+ }
+
+ @Test
+ fun errorCodeAndMessage() {
+ val errorCode = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE
+ val errorMessage = "Test error"
+ val result = input.error<Any?>(errorCode, errorMessage)
+ assertError(result)
+ assertThat(result.errorCode).isEqualTo(errorCode)
+ assertThat(result.errorMessage).isEqualTo(errorMessage)
+ assertThat(result.exception).isNull()
+ }
+
+ @Test
+ fun errorCodeAndMessageAndException() {
+ val errorCode = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE
+ val errorMessage = "Test error"
+ val exception = IOException()
+ val result = input.error<Any?>(errorCode, errorMessage, exception)
+ assertError(result)
+ assertThat(result.errorCode).isEqualTo(errorCode)
+ assertThat(result.errorMessage).isEqualTo(errorMessage)
+ assertThat(result.exception).isSameAs(exception)
+ }
+
+ @Test
+ fun errorCarryResult() {
+ val errorCode = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE
+ val errorMessage = "Test error"
+ val exception = IOException()
+ val result = input.error<Any?>(errorCode, errorMessage, exception)
+ assertError(result)
+ assertThat(result.errorCode).isEqualTo(errorCode)
+ assertThat(result.errorMessage).isEqualTo(errorMessage)
+ assertThat(result.exception).isSameAs(exception)
+
+ val carriedResult = input.error<Int>(result)
+ assertError(carriedResult)
+ assertThat(carriedResult.errorCode).isEqualTo(errorCode)
+ assertThat(carriedResult.errorMessage).isEqualTo(errorMessage)
+ assertThat(carriedResult.exception).isSameAs(exception)
+ }
+
+ @Test
+ fun success() {
+ val value = "Test success"
+ assertSuccess(value, input.success(value))
+ }
+
+ @Test
+ fun deferErrorEnableFirstSdkQ() {
+ assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.Q))
+
+ assertSuccess(input.deferError("Test error", ENABLED_ERROR))
+ }
+
+ @Test
+ fun deferErrorEnableLastSdkQ() {
+ assertSuccess(input.deferError("Test error", ENABLED_ERROR))
+
+ assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.Q))
+ }
+
+ @Test
+ fun deferErrorEnableFirstSdkR() {
+ val error = "Test error"
+ assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R))
+
+ val deferResult = input.deferError(error, ENABLED_ERROR)
+ assertError(deferResult)
+ assertThat(deferResult.errorCode).isNotEqualTo(PackageManager.INSTALL_SUCCEEDED)
+ assertThat(deferResult.errorMessage).isEqualTo(error)
+ assertThat(deferResult.exception).isNull()
+ }
+
+ @Test
+ fun deferErrorEnableLastSdkR() {
+ val error = "Test error"
+ assertSuccess(input.deferError(error, ENABLED_ERROR))
+
+ val result = input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R)
+ assertError(result)
+ assertThat(result.errorCode).isNotEqualTo(PackageManager.INSTALL_SUCCEEDED)
+ assertThat(result.errorMessage).isEqualTo(error)
+ assertThat(result.exception).isNull()
+ }
+
+ @Test
+ fun enableDeferredErrorAndSuccessSdkQ() {
+ val value = "Test success"
+ assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.Q))
+
+ assertSuccess(value, input.success(value))
+ }
+
+ @Test
+ fun enableDeferredErrorAndSuccessSdkR() {
+ val value = "Test success"
+ assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R))
+
+ assertSuccess(value, input.success(value))
+ }
+
+ @Test
+ fun multipleDeferErrorKeepsFirst() {
+ val errorOne = "Test error one"
+ val errorTwo = "Test error two"
+
+ assertSuccess(input.deferError(errorOne, ENABLED_ERROR))
+ assertSuccess(input.deferError(errorTwo, ENABLED_ERROR))
+
+ val result = input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R)
+ assertError(result)
+ assertThat(result.errorCode).isNotEqualTo(PackageManager.INSTALL_SUCCEEDED)
+ assertThat(result.errorMessage).isEqualTo(errorOne)
+ assertThat(result.exception).isNull()
+ }
+
+ @Test
+ fun multipleDisabledErrorsQueriesOnceEnableFirst() {
+ val errorOne = "Test error one"
+ val errorTwo = "Test error two"
+
+ assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R))
+
+ assertSuccess(input.deferError(errorOne, DISABLED_ERROR))
+
+ verify(mockCallback, times(1)).isChangeEnabled(anyLong(), anyString(), anyInt())
+
+ assertSuccess(input.deferError(errorTwo, DISABLED_ERROR))
+
+ verifyNoMoreInteractions(mockCallback)
+ }
+
+ @Test
+ fun multipleDisabledErrorsQueriesOnceEnableSecond() {
+ val errorOne = "Test error one"
+ val errorTwo = "Test error two"
+
+ assertSuccess(input.deferError(errorOne, DISABLED_ERROR))
+
+ verify(mockCallback, never()).isChangeEnabled(anyLong(), anyString(), anyInt())
+
+ assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R))
+
+ verify(mockCallback, times(1)).isChangeEnabled(anyLong(), anyString(), anyInt())
+
+ assertSuccess(input.deferError(errorTwo, DISABLED_ERROR))
+
+ verifyNoMoreInteractions(mockCallback)
+ }
+
+ @After
+ fun verifyReset() {
+ var result = (input as ParseTypeImpl).reset() as ParseResult<*>
+ result.assertReset()
+
+ // The deferred error is not directly accessible, so attempt to re-enable the deferred
+ // error and assert it was also reset.
+ result = input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R)
+ result.assertReset()
+ }
+
+ private fun assertSuccess(result: ParseResult<*>) = assertSuccess(null, result)
+
+ private fun assertSuccess(expected: Any? = null, result: ParseResult<*>) {
+ assertThat(result.isError).isFalse()
+ assertThat(result.isSuccess).isTrue()
+ assertThat(result.result).isSameAs(expected)
+ assertThat(result.errorCode).isEqualTo(PackageManager.INSTALL_SUCCEEDED)
+ assertThat(result.errorMessage).isNull()
+ assertThat(result.exception).isNull()
+ }
+
+ private fun assertError(result: ParseResult<*>) {
+ assertThat(result.isError).isTrue()
+ assertThat(result.isSuccess).isFalse()
+ assertThat(result.result).isNull()
+ }
+
+ private fun ParseResult<*>.assertReset() {
+ assertThat(this.isSuccess).isTrue()
+ assertThat(this.isError).isFalse()
+ assertThat(this.errorCode).isEqualTo(PackageManager.INSTALL_SUCCEEDED)
+ assertThat(this.errorMessage).isNull()
+ assertThat(this.exception).isNull()
+ }
+}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 6c01181..5f12bf0 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -29,6 +29,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -222,6 +223,22 @@
verify(mMockListener, never()).onFinished(any());
}
+ @Test
+ public void testFinish_immediately() {
+ when(mMockController.getState()).thenReturn(mInsetsState);
+ doAnswer(invocation -> {
+ mController.applyChangeInsets(mInsetsState);
+ return null;
+ }).when(mMockController).scheduleApplyChangeInsets(any());
+ mController.finish(true /* shown */);
+ assertEquals(Insets.of(0, 100, 100, 0), mController.getCurrentInsets());
+ verify(mMockController).notifyFinished(eq(mController), eq(true /* shown */));
+ assertFalse(mController.isReady());
+ assertTrue(mController.isFinished());
+ assertFalse(mController.isCancelled());
+ verify(mMockListener).onFinished(mController);
+ }
+
private void assertPosition(Matrix m, Rect original, Rect transformed) {
RectF rect = new RectF(original);
rect.offsetTo(0, 0);
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index f63ec6b..6af887d 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -162,7 +162,6 @@
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="audioserver" />
- <assign-permission name="android.permission.PREEMPT_SOUND_TRIGGER" uid="audioserver" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index a2f9ee9..5925d38 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -24,8 +24,8 @@
* {@hide}
*/
oneway interface IMediaRouter2Manager {
- void notifySessionCreated(in RoutingSessionInfo sessionInfo);
- void notifySessionsUpdated();
+ void notifySessionCreated(int requestId, in RoutingSessionInfo sessionInfo);
+ void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
void notifyPreferredFeaturesChanged(String packageName, in List<String> preferredFeatures);
void notifyRoutesAdded(in List<MediaRoute2Info> routes);
void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 88bcd6a..b694fd0 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -75,6 +75,8 @@
final ConcurrentMap<String, List<String>> mPreferredFeaturesMap = new ConcurrentHashMap<>();
private final AtomicInteger mNextRequestId = new AtomicInteger(1);
+ private final CopyOnWriteArrayList<TransferRequest> mTransferRequests =
+ new CopyOnWriteArrayList<>();
/**
* Gets an instance of media router manager that controls media route of other applications.
@@ -328,6 +330,9 @@
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
+ //TODO: Ensure that every request is eventually removed.
+ mTransferRequests.add(new TransferRequest(requestId, sessionInfo, route));
+
mMediaRouterService.requestCreateSessionWithManager(
client, requestId, sessionInfo.getClientPackageName(), route);
} catch (RemoteException ex) {
@@ -446,6 +451,77 @@
}
}
+ void createSessionOnHandler(int requestId, RoutingSessionInfo sessionInfo) {
+ TransferRequest matchingRequest = null;
+ for (TransferRequest request : mTransferRequests) {
+ if (request.mRequestId == requestId) {
+ matchingRequest = request;
+ break;
+ }
+ }
+
+ if (matchingRequest == null) {
+ return;
+ }
+
+ mTransferRequests.remove(matchingRequest);
+
+ MediaRoute2Info requestedRoute = matchingRequest.mTargetRoute;
+
+ if (sessionInfo == null) {
+ notifyTransferFailed(matchingRequest.mOldSessionInfo, requestedRoute);
+ return;
+ } else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) {
+ Log.w(TAG, "The session does not contain the requested route. "
+ + "(requestedRouteId=" + requestedRoute.getId()
+ + ", actualRoutes=" + sessionInfo.getSelectedRoutes()
+ + ")");
+ notifyTransferFailed(matchingRequest.mOldSessionInfo, requestedRoute);
+ return;
+ } else if (!TextUtils.equals(requestedRoute.getProviderId(),
+ sessionInfo.getProviderId())) {
+ Log.w(TAG, "The session's provider ID does not match the requested route's. "
+ + "(requested route's providerId=" + requestedRoute.getProviderId()
+ + ", actual providerId=" + sessionInfo.getProviderId()
+ + ")");
+ notifyTransferFailed(matchingRequest.mOldSessionInfo, requestedRoute);
+ return;
+ }
+ notifyTransferred(matchingRequest.mOldSessionInfo, sessionInfo);
+ }
+
+ void handleFailureOnHandler(int requestId, int reason) {
+ TransferRequest matchingRequest = null;
+ for (TransferRequest request : mTransferRequests) {
+ if (request.mRequestId == requestId) {
+ matchingRequest = request;
+ break;
+ }
+ }
+
+ if (matchingRequest != null) {
+ mTransferRequests.remove(matchingRequest);
+ notifyTransferFailed(matchingRequest.mOldSessionInfo, matchingRequest.mTargetRoute);
+ return;
+ }
+ notifyRequestFailed(reason);
+ }
+
+ void handleSessionsUpdated(RoutingSessionInfo sessionInfo) {
+ for (TransferRequest request : mTransferRequests) {
+ String sessionId = request.mOldSessionInfo.getId();
+ if (!TextUtils.equals(sessionId, sessionInfo.getId())) {
+ continue;
+ }
+ if (sessionInfo.getSelectedRoutes().contains(request.mTargetRoute.getId())) {
+ notifyTransferred(request.mOldSessionInfo, sessionInfo);
+ mTransferRequests.remove(request);
+ break;
+ }
+ }
+ notifySessionUpdated(sessionInfo);
+ }
+
private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
for (CallbackRecord record: mCallbackRecords) {
record.mExecutor.execute(
@@ -467,16 +543,9 @@
}
}
- void notifySessionCreated(RoutingSessionInfo sessionInfo) {
+ void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
for (CallbackRecord record : mCallbackRecords) {
- record.mExecutor.execute(() -> record.mCallback.onSessionCreated(
- new RoutingController(sessionInfo)));
- }
- }
-
- void notifySessionInfosChanged() {
- for (CallbackRecord record : mCallbackRecords) {
- record.mExecutor.execute(() -> record.mCallback.onSessionsUpdated());
+ record.mExecutor.execute(() -> record.mCallback.onSessionUpdated(sessionInfo));
}
}
@@ -569,7 +638,7 @@
*
* @see #getSelectedRoutes(RoutingSessionInfo)
* @see #getSelectableRoutes(RoutingSessionInfo)
- * @see Callback#onSessionsUpdated()
+ * @see Callback#onSessionUpdated(RoutingSessionInfo)
*/
public void selectRoute(@NonNull RoutingSessionInfo sessionInfo,
@NonNull MediaRoute2Info route) {
@@ -614,7 +683,7 @@
*
* @see #getSelectedRoutes(RoutingSessionInfo)
* @see #getDeselectableRoutes(RoutingSessionInfo)
- * @see Callback#onSessionsUpdated()
+ * @see Callback#onSessionUpdated(RoutingSessionInfo)
*/
public void deselectRoute(@NonNull RoutingSessionInfo sessionInfo,
@NonNull MediaRoute2Info route) {
@@ -667,13 +736,15 @@
return;
}
+ int requestId = mNextRequestId.getAndIncrement();
+ mTransferRequests.add(new TransferRequest(requestId, sessionInfo, route));
+
Client client;
synchronized (sLock) {
client = mClient;
}
if (client != null) {
try {
- int requestId = mNextRequestId.getAndIncrement();
mMediaRouterService.transferToRouteWithManager(
mClient, requestId, sessionInfo.getId(), route);
} catch (RemoteException ex) {
@@ -884,20 +955,12 @@
public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
/**
- * Called when a routing session is created.
- *
- * @param controller the controller to control the created session
+ * Called when a session is changed.
+ * @param sessionInfo the updated session
*/
- public void onSessionCreated(@NonNull RoutingController controller) {}
+ public void onSessionUpdated(@NonNull RoutingSessionInfo sessionInfo) {}
/**
- * Called when at least one session info is changed.
- * Call {@link #getActiveSessions()} to get current active session info.
- */
- public void onSessionsUpdated() {}
-
- //TODO: Call this.
- /**
* Called when media is transferred.
*
* @param oldSession the previous session
@@ -906,7 +969,6 @@
public void onTransferred(@NonNull RoutingSessionInfo oldSession,
@Nullable RoutingSessionInfo newSession) { }
- //TODO: Call this.
/**
* Called when {@link #transfer(RoutingSessionInfo, MediaRoute2Info)} fails.
*/
@@ -971,25 +1033,37 @@
}
}
+ static final class TransferRequest {
+ public final int mRequestId;
+ public final RoutingSessionInfo mOldSessionInfo;
+ public final MediaRoute2Info mTargetRoute;
+
+ TransferRequest(int requestId, @NonNull RoutingSessionInfo oldSessionInfo,
+ @NonNull MediaRoute2Info targetRoute) {
+ mRequestId = requestId;
+ mOldSessionInfo = oldSessionInfo;
+ mTargetRoute = targetRoute;
+ }
+ }
+
class Client extends IMediaRouter2Manager.Stub {
@Override
- public void notifySessionCreated(RoutingSessionInfo sessionInfo) {
- mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifySessionCreated,
- MediaRouter2Manager.this, sessionInfo));
+ public void notifySessionCreated(int requestId, RoutingSessionInfo sessionInfo) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2Manager::createSessionOnHandler,
+ MediaRouter2Manager.this, requestId, sessionInfo));
}
@Override
- public void notifySessionsUpdated() {
- mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifySessionInfosChanged,
- MediaRouter2Manager.this));
- // do nothing
+ public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
+ mHandler.sendMessage(obtainMessage(MediaRouter2Manager::handleSessionsUpdated,
+ MediaRouter2Manager.this, sessionInfo));
}
@Override
public void notifyRequestFailed(int requestId, int reason) {
// Note: requestId is not used.
- mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyRequestFailed,
- MediaRouter2Manager.this, reason));
+ mHandler.sendMessage(obtainMessage(MediaRouter2Manager::handleFailureOnHandler,
+ MediaRouter2Manager.this, requestId, reason));
}
@Override
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 2e038e6..68f2964 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Collection;
@@ -29,6 +30,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* A media route discovery preference describing the features of routes that media router
@@ -169,8 +171,9 @@
Bundle mExtras;
public Builder(@NonNull List<String> preferredFeatures, boolean activeScan) {
- mPreferredFeatures = new ArrayList<>(Objects.requireNonNull(preferredFeatures,
- "preferredFeatures must not be null"));
+ Objects.requireNonNull(preferredFeatures, "preferredFeatures must not be null");
+ mPreferredFeatures = preferredFeatures.stream().filter(str -> !TextUtils.isEmpty(str))
+ .collect(Collectors.toList());
mActiveScan = activeScan;
}
@@ -211,8 +214,9 @@
*/
@NonNull
public Builder setPreferredFeatures(@NonNull List<String> preferredFeatures) {
- mPreferredFeatures = new ArrayList<>(Objects.requireNonNull(preferredFeatures,
- "preferredFeatures must not be null"));
+ Objects.requireNonNull(preferredFeatures, "preferredFeatures must not be null");
+ mPreferredFeatures = preferredFeatures.stream().filter(str -> !TextUtils.isEmpty(str))
+ .collect(Collectors.toList());
return this;
}
diff --git a/media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl b/media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
index 8033307..06c3907 100644
--- a/media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
+++ b/media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
@@ -39,10 +39,4 @@
* one of the handles from the returned list.
*/
ISoundTriggerModule attach(int handle, ISoundTriggerCallback callback);
-
- /**
- * Notify the service that external input capture is taking place. This may cause some of the
- * active recognitions to be aborted.
- */
- void setExternalCaptureState(boolean active);
}
\ No newline at end of file
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 77e8f97..6ca564f 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -231,9 +231,10 @@
addRouterCallback(new RouteCallback() {});
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
- public void onSessionCreated(MediaRouter2Manager.RoutingController controller) {
- if (TextUtils.equals(mPackageName, controller.getClientPackageName())
- && createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1)) {
+ public void onTransferred(RoutingSessionInfo oldSessionInfo,
+ RoutingSessionInfo newSessionInfo) {
+ if (TextUtils.equals(mPackageName, newSessionInfo.getClientPackageName())
+ && newSessionInfo.getSelectedRoutes().contains(ROUTE_ID1)) {
latch.countDown();
}
}
@@ -268,8 +269,9 @@
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
- public void onSessionCreated(MediaRouter2Manager.RoutingController controller) {
- assertNotNull(controller);
+ public void onTransferred(RoutingSessionInfo oldSessionInfo,
+ RoutingSessionInfo newSessionInfo) {
+ assertNotNull(newSessionInfo);
onSessionCreatedLatch.countDown();
}
});
@@ -352,8 +354,9 @@
// create a controller
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
- public void onSessionCreated(MediaRouter2Manager.RoutingController controller) {
- assertNotNull(controller);
+ public void onTransferred(RoutingSessionInfo oldSessionInfo,
+ RoutingSessionInfo newSessionInfo) {
+ assertNotNull(newSessionInfo);
onSessionCreatedLatch.countDown();
}
});
@@ -383,13 +386,12 @@
addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
- public void onSessionsUpdated() {
- List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
- if (sessions.size() != 2) {
+ public void onSessionUpdated(RoutingSessionInfo updatedSessionInfo) {
+ if (!TextUtils.equals(sessionInfo.getId(), updatedSessionInfo.getId())) {
return;
}
- if (sessions.get(1).getVolume() == targetVolume) {
+ if (updatedSessionInfo.getVolume() == targetVolume) {
volumeChangedLatch.countDown();
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index 3ee92bd7..df82753 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -150,7 +150,7 @@
ex.rethrowFromSystemServer();
}
- mAutoHideController.addAutoHideUiElement(new AutoHideUiElement() {
+ mAutoHideController.setNavigationBar(new AutoHideUiElement() {
@Override
public void synchronizeState() {
// No op.
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 02604d8..cd45fc9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -65,6 +65,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
@@ -225,6 +226,7 @@
KeyguardIndicationController keyguardIndicationController,
DismissCallbackRegistry dismissCallbackRegistry,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+ Lazy<NotificationShadeDepthController> depthControllerLazy,
/* Car Settings injected components. */
CarNavigationBarController carNavigationBarController) {
super(
@@ -304,6 +306,7 @@
phoneStatusBarPolicy,
keyguardIndicationController,
dismissCallbackRegistry,
+ depthControllerLazy,
statusBarTouchableRegionManager);
mUserSwitcherController = userSwitcherController;
mScrimController = scrimController;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 1baa1f6..e163173 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -51,6 +51,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
@@ -200,6 +201,7 @@
KeyguardIndicationController keyguardIndicationController,
DismissCallbackRegistry dismissCallbackRegistry,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+ Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
CarNavigationBarController carNavigationBarController) {
return new CarStatusBar(
context,
@@ -278,6 +280,7 @@
keyguardIndicationController,
dismissCallbackRegistry,
statusBarTouchableRegionManager,
+ notificationShadeDepthControllerLazy,
carNavigationBarController);
}
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 944294b..a5bac27 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Berging"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Gedeelde data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Bekyk en wysig gedeelde data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Daar is geen gedeelde data vir hierdie gebruiker nie."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Kon nie gedeelde data gaan haal nie. Probeer weer."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Gedeelde data-ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Verval op <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Kon nie die gedeelde data uitvee nie."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Daar is geen huurkontrakte vir hierdie gedeelde data verkry nie. Wil jy dit uitvee?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Programme wat data deel"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Geen beskrywing is deur die program voorsien nie."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Huurkontrak verval op <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profiel-inligting"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Voordat jy \'n beperkte profiel kan skep, moet jy \'n skermslot opstel om jou programme en persoonlike data te beskerm."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Stel slot op"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Skakel oor na <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Gas"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 0a7b045..1681fdb 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"ማከማቻ"</string>
<string name="shared_data_title" msgid="1017034836800864953">"የተጋራ ውሂብ"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"የተጋራ ውሂብን ይመልከቱ እና ያሻሽሉ"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ለዚህ ተጠቃሚ ምንም የተጋራ ውሂብ የለም።"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"የተጋራውን ውሂብ በማግኘት ላይ ስሕተት ነበረ። እንደገና ይሞክሩ።"</string>
<string name="blob_id_text" msgid="8680078988996308061">"የተጋራ ውሂብ መታወቂያ፦ <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"በ<xliff:g id="DATE">%s</xliff:g> ላይ የአገልግሎት ጊዜው ያበቃል"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"የተጋራውን ውሂብ በመሰረዝ ላይ ስሕተት ነበረ።"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ለዚህ የተጋራ ውሂብ ምንም የሚያስፈልጉ ኪራዮች የሉም። ሊሰርዙት ይፈልጋሉ?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"ውሂብ የሚጋሩ መተግበሪያዎች"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"በመተግበሪያው ምንም ዝርዝር መረጃ አልተሰጠም።"</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"ኪራይ በ<xliff:g id="DATE">%s</xliff:g> ላይ አገልግሎት ጊዜው ያበቃል"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"የመገለጫ መረጃ"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"የተገደበ መገለጫ መፍጠር ከመቻልዎ በፊት መተግበሪያዎችዎን እና የግል ውሂብዎን ለመጠበቅ ቁልፍ ማያ ገጽ ማዋቀር አለብዎት።"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ቁልፍ አዘጋጅ"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"ወደ <xliff:g id="USER_NAME">%s</xliff:g> ቀይር"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"እንግዳ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 03dbfb0..abd1e03 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -523,18 +523,14 @@
<skip />
<!-- no translation found for shared_data_summary (5516326713822885652) -->
<skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ما مِن بيانات مشتركة لهذا المستخدم."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"حدث خطأ أثناء جلب البيانات المشتركة. يُرجى إعادة المحاولة."</string>
<!-- no translation found for blob_id_text (8680078988996308061) -->
<skip />
<!-- no translation found for blob_expires_text (7882727111491739331) -->
<skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"حدث خطأ أثناء حذف البيانات المشتركة."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ما مِن عمليات تأجير مطلوبة لهذه المعلومات المشتركة. هل تريد حذفها؟"</string>
<!-- no translation found for accessor_info_title (8289823651512477787) -->
<skip />
<!-- no translation found for accessor_no_description_text (7510967452505591456) -->
@@ -564,4 +560,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"معلومات الملف الشخصي"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"قبل أن تتمكن من إنشاء ملف شخصي مقيد، يلزمك إعداد تأمين للشاشة لحماية تطبيقاتك وبياناتك الشخصية."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"تعيين التأمين"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 06df8f7..a1c00a3 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"ষ্ট’ৰেজ"</string>
<string name="shared_data_title" msgid="1017034836800864953">"শ্বেয়াৰ কৰা ডেটা"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"শ্বেয়াৰ কৰা ডেটা চাওক আৰু সংশোধন কৰক"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"এই ব্যৱহাৰকাৰীজনৰ বাবে কোনো শ্বেয়াৰ কৰা ডেটা নাই।"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"শ্বেয়াৰ কৰা ডেটা আহৰণ কৰোঁতে আসোঁৱাহ হৈছে। পুনৰ চেষ্টা কৰক।"</string>
<string name="blob_id_text" msgid="8680078988996308061">"শ্বেয়াৰ কৰা ডেটাৰ আইডি: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g>ত ম্যাদ উকলিব"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"শ্বেয়াৰ কৰা ডেটা মচোঁতে আসোঁৱাহ হৈছে।"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"শ্বেয়াৰ কৰা এই ডেটাখিনিৰ বাবে কোনো লীজ লোৱা হোৱা নাই। আপুনি ইয়াক মচিবনে?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"ডেটা শ্বেয়াৰ কৰা এপ্সমূহ"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"এপ্টোৱে কোনো বিৱৰণ দিয়া নাই।"</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"<xliff:g id="DATE">%s</xliff:g>ত লীজৰ ম্যাদ উকলিব"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"প্ৰ\'ফাইলৰ তথ্য"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"আপুনি সীমিত প্ৰ\'ফাইল এটা সৃষ্টি কৰাৰ আগেয়ে, আপোনাৰ ব্যক্তিগত ডেটা আৰু এপবিলাকক সুৰক্ষিত কৰিবলৈ স্ক্ৰীণ লক এটা নিৰ্ধাৰণ কৰিব লাগিব।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"লক ছেট কৰক"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 56f3640..50451e1 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Yaddaş"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Paylaşılan data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Paylaşılan dataya baxın və ona dəyişiklik edin"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Bu istifadəçi üçün paylaşılan data yoxdur."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Paylaşılan datanı əldə edərkən xəta oldu. Yenidən cəhd edin."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Paylaşılan data ID\'si: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> tarixində müddəti bitir"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Paylaşılan datanı silərkən xəta oldu."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Bu paylaşılan data üçün lizinq əldə edilməyib. Onu silmək istərdiniz?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Data paylaşan tətbiqlər"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Tətbiq tərəfindən heç bir təsvir təmin edilməyib."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"İcarə müddəti <xliff:g id="DATE">%s</xliff:g> tarixində bitir"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profil info"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Məhdudlaşdırılmış profil yaratmadan öncə, Siz tətbiqlərinizi və şəxsi datanızı qorumaq üçün ekran kilidi quraşdırmalısınız."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Kilid ayarlayın"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index e81dbc3..0e39d7f 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -514,16 +514,12 @@
<string name="storage_category" msgid="2287342585424631813">"Memorijski prostor"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Deljeni podaci"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Pregledajte i izmenite deljene podatke"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nema deljenih podataka za ovog korisnika."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Došlo je do greške pri preuzimanju deljenih podataka. Probajte ponovo."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID deljenih podataka: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Ističe: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Došlo je do greške pri brisanju deljenih podataka."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Nema kupljenih zakupa za ove deljene podatke. Želite li da ih izbrišete?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikacije koje dele podatke"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"U aplikaciji nije naveden nijedan opis."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Iznajmljivanje ističe: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -548,4 +544,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Podaci o profilu"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Da biste mogli da napravite ograničeni profil, treba da podesite zaključavanje ekrana da biste zaštitili aplikacije i lične podatke."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Podesi zaključavanje"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 01f3eed..328762c 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -515,16 +515,12 @@
<string name="storage_category" msgid="2287342585424631813">"Сховішча"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Абагуленыя даныя"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Прагляд і змяненне абагуленых даных"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Для гэтага карыстальніка няма абагуленых даных."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Падчас атрымання абагуленых даных узнікла памылка. Паўтарыце спробу."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Ідэнтыфікатар абагуленых даных: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Тэрмін дзеяння заканчваецца <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Падчас выдалення абагуленых даных узнікла памылка."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Для гэтых абагуленых даных няма дазволаў. Выдаліць іх?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Праграмы, якія абагульваюць даныя"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"У праграмы адсутнічае апісанне."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Тэрмін дзеяння арэнды завяршаецца <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Звесткi профiлю"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Перш чым вы зможаце стварыць профіль з абмежаваннямi, вам трэба наладзіць блакiроўку экрана для абароны сваiх дадаткаў і асабістай інфармацыі."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Усталёўка блакiроўкi"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 6e15f30..690cc49 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Хранилище"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Споделени данни"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Преглед и промяна на споделените данни"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Няма споделени данни за този потребител."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"При извличането на споделените данни възникна грешка. Опитайте отново."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Идентификатор на споделените данни: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Изтича на <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"При изтриването на споделените данни възникна грешка."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Няма придобити споделяния за тези споделени данни. Искате ли да ги изтриете?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Приложения, споделящи данни"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Няма описание, предоставено от приложението."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Споделянето приключва на <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Инф. за потр. профил"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Преди да можете да създадете потребителски профил с ограничена функционалност, трябва да настроите заключения екран, за да защитите приложенията и личните си данни."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Задаване на заключване"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 8805c21..017936f 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -232,8 +232,7 @@
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP অ্যাড্রেস ও পোর্ট"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR কোড স্ক্যান করুন"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR কোড স্ক্যান করে ওয়াই-ফাই ব্যবহার করে ডিভাইস যোগ করুন"</string>
- <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) -->
- <skip />
+ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"একটি ওয়াই-ফাই নেটওয়ার্কের সাথে কানেক্ট করুন"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"ত্রুটি প্রতিবেদনের শর্টকাট"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"সমস্যার তথ্য ক্যাপচার করতে পাওয়ার মেনুতে একটি বোতাম দেখান"</string>
@@ -432,8 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"আনুমানিক <xliff:g id="TIME">%1$s</xliff:g> পর্যন্ত চলবে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"আনুমানিক <xliff:g id="TIME">%1$s</xliff:g> পর্যন্ত চলবে"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> পর্যন্ত"</string>
- <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) -->
- <skip />
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"ব্যাটারির চার্জ <xliff:g id="TIME">%1$s</xliff:g>-এ শেষ হয়ে যেতে পারে"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> এর থেকেও কম বাকি আছে"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"আর <xliff:g id="THRESHOLD">%1$s</xliff:g>-এর কম চার্জ বাকি আছে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"আরও <xliff:g id="TIME_REMAINING">%1$s</xliff:g>-এর বেশি চলবে (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -511,36 +509,21 @@
<string name="media_transfer_this_device_name" msgid="2716555073132169240">"ফেনের স্পিকার"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"কানেক্ট করতে সমস্যা হচ্ছে। ডিভাইস বন্ধ করে আবার চালু করুন"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ওয়্যার অডিও ডিভাইস"</string>
- <!-- no translation found for help_label (3528360748637781274) -->
- <skip />
- <!-- no translation found for storage_category (2287342585424631813) -->
- <skip />
- <!-- no translation found for shared_data_title (1017034836800864953) -->
- <skip />
- <!-- no translation found for shared_data_summary (5516326713822885652) -->
- <skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
- <!-- no translation found for blob_id_text (8680078988996308061) -->
- <skip />
- <!-- no translation found for blob_expires_text (7882727111491739331) -->
- <skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
- <!-- no translation found for accessor_info_title (8289823651512477787) -->
- <skip />
- <!-- no translation found for accessor_no_description_text (7510967452505591456) -->
- <skip />
- <!-- no translation found for accessor_expires_text (4625619273236786252) -->
- <skip />
- <!-- no translation found for delete_blob_text (2819192607255625697) -->
- <skip />
- <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) -->
- <skip />
+ <string name="help_label" msgid="3528360748637781274">"সহায়তা ও মতামত"</string>
+ <string name="storage_category" msgid="2287342585424631813">"স্টোরেজ"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"শেয়ার্ড ডেটা"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"শেয়ার্ড ডেটা দেখুন ও পরিবর্তন করুন"</string>
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ব্যবহারকারীর জন্য কোনও শেয়ার করা ডেটা নেই।"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"শেয়ার করা ডেটা পেতে গিয়ে কোনও সমস্যা হয়েছে। আবার চেষ্টা করুন।"</string>
+ <string name="blob_id_text" msgid="8680078988996308061">"শেয়ার্ড ডেটা আইডি: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
+ <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> তারিখে শেষ হয়ে যাবে"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"শেয়ার করা ডেটা মুছতে গিয়ে কোনও সমস্যা হয়েছে।"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"শেয়ার করা এই ডেটার জন্য কোনও লিজ নেওয়া হয়নি। আপনি কি এটি মুছে দিতে চান?"</string>
+ <string name="accessor_info_title" msgid="8289823651512477787">"এই অ্যাপ শেয়ার্ড ডেটা অ্যাক্সেস করছে"</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"অ্যাপ কোনও বিবরণ প্রদান করেনি।"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"<xliff:g id="DATE">%s</xliff:g> তারিখে লিজের মেয়াদ শেষ হয়ে যাবে"</string>
+ <string name="delete_blob_text" msgid="2819192607255625697">"শেয়ার্ড ডেটা মুছে দিন"</string>
+ <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"আপনি কি সত্যিই এই শেয়ার্ড ডেটা মুছে দিতে চান?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"ব্যবহারকারীদের তাঁদের নিজস্ব অ্যাপ্লিকেশন এবং কন্টেন্ট আছে"</string>
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"আপনি আপনার অ্যাকাউন্ট থেকে অ্যাপ্লিকেশন এবং কন্টেন্ট অ্যাক্সেস সীমাবদ্ধ করতে পারেন"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"ব্যবহারকারী"</string>
@@ -560,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"প্রোফাইল তথ্য"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"আপনি একটি সীমাবদ্ধযুক্ত প্রোফাইল তৈরি করার আগে, আপনাকে আপনার অ্যাপ্লিকেশন এবং ব্যক্তিগত ডেটা সুরক্ষিত করার জন্য একটি স্ক্রিন লক সেট-আপ করতে হবে।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"লক সেট করুন"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 188c2f5..a1b1afc 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -514,16 +514,12 @@
<string name="storage_category" msgid="2287342585424631813">"Pohrana"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Dijeljeni podaci"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Prikaz i izmjena dijeljenih podataka"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nema dijeljenih podataka za ovog korisnika."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Došlo je do greške prilikom dohvaćanja dijeljenih podataka. Ponovite."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID dijeljenih podataka: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Ističe dana <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Došlo je do greške prilikom brisanja dijeljenih podataka."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Nema preuzetih najmova za ove dijeljene podatke. Želite li ih izbrisati?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikacije koje dijele podatke"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"U aplikaciji nije naveden opis."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Najam ističe dana <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -548,4 +544,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Podaci o profilu"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Prije nego vam se omogući kreiranje ograničenog profila, morate postaviti zaključavanje ekrana da biste zaštitili svoje aplikacije i lične podatke."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Postaviti zaključavanje"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Prelazak na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 7fadf93..a1b2da8 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Emmagatzematge"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Dades compartides"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Mostra i modifica les dades compartides"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"No hi ha dades compartides per a aquest usuari."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"S\'ha produït un error en recollir les dades compartides. Torna-ho a provar."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Identificador de dades compartides: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
- <string name="blob_expires_text" msgid="7882727111491739331">"Caduca el dia <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="blob_expires_text" msgid="7882727111491739331">"Caduquen el dia <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"S\'ha produït un error en suprimir les dades compartides."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"No s\'ha adquirit cap arrendament d\'aquestes dades. Vols suprimir-les?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplicacions que comparteixen dades"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"L\'aplicació no ha proporcionat cap descripció."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"La concessió caduca el dia <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informació de perfil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Per crear un perfil restringit, has de configurar una pantalla de bloqueig per protegir les aplicacions i les dades personals."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Defineix un bloqueig"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index f5d8465..bbf29bb 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -515,16 +515,12 @@
<string name="storage_category" msgid="2287342585424631813">"Úložiště"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Sdílená data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Zobrazit a upravit sdílená data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Pro tohoto uživatele nejsou k dispozici žádná sdílená data."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Při načítání sdílených dat došlo k chybě. Zkuste to znovu."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID sdílených dat: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Platnost vyprší <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Při mazání sdílených dat došlo k chybě."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Pro tato sdílená data nejsou k dispozici žádné smlouvy. Chcete je smazat?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikace, které sdílejí data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Aplikace neposkytuje žádný popis."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Pronájem vyprší <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informace o profilu"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Před vytvořením omezeného profilu je nutné nejprve nastavit zámek obrazovky k ochraně aplikací a dat."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastavit zámek"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 07a90d6..20b7ae1 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Lager"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Delte data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Se og rediger delte data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Der er ingen delte data for denne bruger."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Der opstod en fejl, da de delte data skulle hentes. Prøv igen."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Id for delte data: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Udløber <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Der opstod en fejl, da de delte data skulle slettes."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Der er ingen lejeaftaler i forbindelse med disse data. Vil du slette dem?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps, der deler data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Der er ikke angivet nogen beskrivelse af appen."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Leasingen udløber <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profiloplysninger"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Før du kan oprette en begrænset profil, skal du oprette en skærmlås for at beskytte dine apps og personlige data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurer låseskærmen"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index f151bc3..1a28985 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -513,18 +513,14 @@
<string name="storage_category" msgid="2287342585424631813">"Speicher"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Geteilte Daten"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Geteilte Daten anzeigen und ändern"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Es gibt keine geteilten Daten für diesen Nutzer."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Beim Abrufen der geteilten Daten ist ein Fehler aufgetreten. Versuch es noch einmal."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID für geteilte Daten: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Läuft am <xliff:g id="DATE">%s</xliff:g> ab"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Beim Löschen der geteilten Daten ist ein Fehler aufgetreten."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Für diese geteilten Daten gibt es keine Freigaben. Möchtest du sie löschen?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps, die Daten teilen"</string>
- <string name="accessor_no_description_text" msgid="7510967452505591456">"Keine Beschreibung der App verfügbar."</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"Keine von der App bereitgestellte Beschreibung verfügbar."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Freigabe läuft am <xliff:g id="DATE">%s</xliff:g> ab"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"Geteilte Daten löschen"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Bist du sicher, dass du diese geteilten Daten löschen möchtest?"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profilinformationen"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Vor dem Erstellen eines eingeschränkten Profils musst du eine Displaysperre einrichten, um deine Apps und personenbezogenen Daten zu schützen."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Sperre einrichten"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 094e1d7..9c1842a 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Αποθηκευτικός χώρος"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Κοινόχρηστα δεδομένα"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Προβολή και τροποποίηση κοινόχρηστων δεδομένων"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Δεν υπάρχουν κοινόχρηστα δεδομένα για αυτόν τον χρήστη."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Παρουσιάστηκε σφάλμα κατά τη λήψη των κοινόχρηστων δεδομένων. Επανάληψη."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Αναγνωριστικό κοινόχρηστων δεδομένων: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Λήγει στις <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Παρουσιάστηκε σφάλμα κατά τη διαγραφή των κοινόχρηστων δεδομένων."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Δεν αποκτήθηκαν μισθώσεις για αυτά τα κοινόχρηστα δεδομένα. Θέλετε να τα διαγράψετε;"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Εφαρμογές που κάνουν κοινή χρήση δεδομένων"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Δεν παρέχεται περιγραφή από την εφαρμογή."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Λήξη άδειας στις <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Πληροφορίες προφίλ"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Προκειμένου να μπορέσετε να δημιουργήσετε ένα περιορισμένο προφίλ, θα πρέπει να δημιουργήσετε ένα κλείδωμα οθόνης για την προστασία των εφαρμογών και των προσωπικών δεδομένων σας."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Ορισμός κλειδώματος"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index fc1adbb..4cc2744 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Shared data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"View and modify shared data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"There is no shared data for this user."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"There was an error fetching shared data. Try again."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Shared data ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expires on <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"There was an error deleting the shared data."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"There are no leases acquired for this shared data. Would you like to delete it?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps sharing data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"No description provided by the app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Lease expires on <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profile info"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index fc1adbb..4cc2744 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Shared data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"View and modify shared data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"There is no shared data for this user."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"There was an error fetching shared data. Try again."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Shared data ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expires on <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"There was an error deleting the shared data."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"There are no leases acquired for this shared data. Would you like to delete it?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps sharing data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"No description provided by the app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Lease expires on <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profile info"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index fc1adbb..4cc2744 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Shared data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"View and modify shared data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"There is no shared data for this user."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"There was an error fetching shared data. Try again."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Shared data ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expires on <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"There was an error deleting the shared data."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"There are no leases acquired for this shared data. Would you like to delete it?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps sharing data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"No description provided by the app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Lease expires on <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profile info"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index fc1adbb..4cc2744 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Shared data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"View and modify shared data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"There is no shared data for this user."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"There was an error fetching shared data. Try again."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Shared data ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expires on <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"There was an error deleting the shared data."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"There are no leases acquired for this shared data. Would you like to delete it?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps sharing data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"No description provided by the app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Lease expires on <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profile info"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you\'ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 1736429..e935a74 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Shared data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"View and modify shared data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"There is no shared data for this user."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"There was an error fetching shared data. Try again."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Shared data ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expires at <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"There was an error deleting the shared data."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"There are no leases acquired for this shared data. Would you like to delete it?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps sharing data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"No description provided by the app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Lease expires at <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profile info"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Before you can create a restricted profile, you’ll need to set up a screen lock to protect your apps and personal data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Set lock"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Switch to <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index a881b3c..cc3cd11 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -510,19 +510,15 @@
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Error al establecer la conexión. Apaga el dispositivo y vuelve a encenderlo."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y comentarios"</string>
- <string name="storage_category" msgid="2287342585424631813">"Storage"</string>
+ <string name="storage_category" msgid="2287342585424631813">"Almacenamiento"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Datos compartidos"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ver y modificar los datos compartidos"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"No hay datos compartidos para este usuario."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Se produjo un error al recuperar los datos compartidos. Vuelve a intentarlo."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID de datos compartidos: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Vence el <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Se produjo un error al borrar los datos compartidos."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"No hay concesiones adquiridas para estos datos compartidos. ¿Quieres borrarlos?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps que comparten datos"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"La app no proporcionó una descripción."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"La asignación de tiempo vence el <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Datos del perfil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restringido, debes configurar un bloqueo de pantalla que proteja tus aplicaciones y datos personales."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Configurar bloqueo"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8d80527..e85187b 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -431,7 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"Duración aproximada hasta: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"Hasta: <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Es probable que te quedes sin batería sobre las <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Es probable que te quedes sin batería sobre esta hora: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"Queda menos del <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"Queda más del <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -510,19 +510,15 @@
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"No se ha podido conectar; reinicia el dispositivo"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de audio con cable"</string>
<string name="help_label" msgid="3528360748637781274">"Ayuda y sugerencias"</string>
- <string name="storage_category" msgid="2287342585424631813">"Memoria"</string>
+ <string name="storage_category" msgid="2287342585424631813">"Almacenamiento"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Datos compartidos"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ver y modificar los datos compartidos"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"No hay datos compartidos de este usuario."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"No se han podido generar datos compartidos. Inténtalo de nuevo."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID de datos compartidos: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Caduca el <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"No se han podido eliminar los datos compartidos."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"No hay ninguna concesión sobre estos datos compartidos. ¿Quieres eliminarlos?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplicaciones que comparten datos"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"La aplicación no ofrece ninguna descripción."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"La concesión caduca el <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Información del perfil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restringido, debes configurar una pantalla de bloqueo que proteja tus aplicaciones y datos personales."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index f4e0e73..c9bd7a0 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Salvestusruum"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Jagatud andmed"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Vaadake ja muutke jagatud andmeid"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Selle kasutaja kohta pole jagatud andmeid."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Jagatud andmete toomisel ilmnes viga. Proovige uuesti."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Jagatud andmete ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Aegub <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Jagatud andmete kustutamisel ilmnes viga."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Nende jagatud andmete jaoks pole õigusi hangitud. Kas soovite need kustutada?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Andmeid jagavad rakendused"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Rakendus ei esita kirjeldust."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Rendiperiood lõpeb <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profiili teave"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Enne piiratud profiili loomist peate seadistama lukustusekraani, et oma rakendusi ja isiklikke andmeid kaitsta."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Määra lukk"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index e516222..42c702a 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -509,23 +509,19 @@
<string name="media_transfer_this_device_name" msgid="2716555073132169240">"Telefonoaren bozgorailua"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Arazoren bat izan da konektatzean. Itzali gailua eta pitz ezazu berriro."</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
- <string name="help_label" msgid="3528360748637781274">"Laguntza eta iritzia"</string>
- <string name="storage_category" msgid="2287342585424631813">"Memoria"</string>
+ <string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
+ <string name="storage_category" msgid="2287342585424631813">"Biltegiratzea"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Partekatutako datuak"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ikusi eta aldatu partekatutako datuak"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Ez dago erabiltzaile honen datu partekaturik."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Errore bat gertatu da datu partekatuak eskuratzean. Saiatu berriro."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Partekatutako datuen IDa: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Iraungitze-data: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Errore bat gertatu da datu partekatuak ezabatzean."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Ez da eskuratu alokairu-hitzarmenik datu partekatu hauetarako. Ezabatu egin nahi dituzu?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Datuak partekatzen dituzten aplikazioak"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Aplikazioak ez du azalpenik eman."</string>
- <string name="accessor_expires_text" msgid="4625619273236786252">"Alokatzearen iraungitze-data: <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"Lagapenaren iraungitze-data: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"Ezabatu partekatutako datuak"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Ziur partekatutako datuak ezabatu nahi dituzula?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"Erabiltzaileek euren aplikazioak eta edukia dituzte."</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profileko informazioa"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Profil murriztua sortu aurretik, aplikazioak eta datu pertsonalak babesteko, pantaila blokeatzeko metodo bat konfiguratu beharko duzu."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Ezarri blokeoa"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index cfdab50..2a284ee 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"فضای ذخیرهسازی"</string>
<string name="shared_data_title" msgid="1017034836800864953">"دادههای همرسانیشده"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"مشاهده و تغییر دادههای همرسانیشده"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"هیچ داده همرسانیشدهای برای این کاربر وجود ندارد."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"هنگام واکشی دادههای همرسانیشده خطایی رخ داد. دوباره امتحان کنید."</string>
<string name="blob_id_text" msgid="8680078988996308061">"شناسه دادههای همرسانیشده: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"تاریخ انقضا <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"هنگام حذف دادههای همرسانیشده خطایی رخ داد."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"هیچ اجارهای برای این دادههای همرسانیشده درخواست نشده است. میخواهید آن را حذف کنید؟"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"دادههای همرسانی برنامهها"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"برنامه هیچ توضیحی ارائه نکرده است."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"تاریخ انقضای کرایه <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"اطلاعات نمایه"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"قبل از ایجاد یک نمایه محدود، باید یک قفل صفحه را برای محافظت از برنامهها و دادههای شخصی خود تنظیم کنید."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"تنظیم قفل"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 57ab974..76e8f5b 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Tallennustila"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Jaettu data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Katso ja muokkaa jaettua dataa"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Tälle käyttäjälle ei löydy jaettua dataa."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Jaettua dataa noudettaessa tapahtui virhe. Yritä uudelleen."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Jaetun datan tunnus: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Vanhenee <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Jaettua dataa poistettaessa tapahtui virhe."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Tälle jaetulle datalle ei ole hankittu varausta. Haluatko poistaa datan?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Dataa jakavat sovellukset"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Sovelluksella ei ole kuvausta."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Vuokra-aika päättyy <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profiilin tiedot"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Ennen kuin voit luoda rajoitetun profiilin, määritä näytön lukitus, joka suojelee sovelluksiasi ja henkilökohtaisia tietojasi."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Aseta lukitus"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 10ed6c1..4c599f0 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Stockage"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Données partagées"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Afficher et modifier les données partagées"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Il n\'y a aucune donnée partagée pour cet utilisateur."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Une erreur s\'est produite lors de la récupération des données partagées. Réessayez."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Identifiant de données partagées : <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expirent le <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Une erreur s\'est produite lors de la suppression des données partagées."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Il n\'y a aucun bail octroyé pour ces données partagées. Souhaitez-vous les supprimer?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Applications qui partagent des données"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Aucune description fournie par l\'application."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Le bail expire le <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informations de profil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Avant de créer un profil limité, vous devez définir un écran de verrouillage pour protéger vos applications et vos données personnelles."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 014a175..8e8f09d 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Stockage"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Données partagées"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Afficher et modifier les données partagées"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Il n\'y a pas de données partagées pour cet utilisateur."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Une erreur s\'est produite lors de la récupération des données partagées. Réessayez."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID de données partagées : <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Date d\'expiration : <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Une erreur s\'est produite lors de la suppression des données partagées."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Aucun bail acquis pour ces données partagées. Voulez-vous les supprimer ?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Applications qui partagent des données"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Aucune description fournie par l\'application."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Date d\'expiration des données partagées : <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informations de profil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Avant de créer un profil limité, vous devez définir un écran de verrouillage pour protéger vos applications et vos données personnelles."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 46c5128..e17da89 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Almacenamento"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Datos compartidos"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Consulta e modifica os datos compartidos"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Non hai datos compartidos para este usuario."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Produciuse un erro ao obter os datos compartidos. Téntao de novo."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Código de identificación dos datos compartidos: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Caduca o <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Produciuse un erro ao eliminar os datos compartidos."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Non se adquiriu ningunha concesión para estes datos compartidos. Queres eliminalos?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplicacións que comparten datos"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"A aplicación non forneceu ningunha descrición."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"O alugueiro caduca o <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Información do perfil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restrinxido, precisarás configurar un bloqueo da pantalla para protexer as túas aplicacións e datos persoais."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 564b703..207e07f 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -232,8 +232,7 @@
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ઍડ્રેસ & પોર્ટ"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR કોડ સ્કૅન કરો"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR કોડને સ્કૅન કરીને વાઇ-ફાઇ પર ડિવાઇસનું જોડાણ બનાવો"</string>
- <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) -->
- <skip />
+ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"કૃપા કરીને વાઇ-ફાઇ નેટવર્કથી કનેક્ટ કરો"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ડિબગ, ડેવ"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"બગ રિપોર્ટ શોર્ટકટ"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"બગ રિપોર્ટ લેવા માટે પાવર મેનૂમાં એક બટન બતાવો"</string>
@@ -432,8 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"લગભગ <xliff:g id="TIME">%1$s</xliff:g> સુધી ચાલવી જોઈએ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"લગભગ <xliff:g id="TIME">%1$s</xliff:g> સુધી ચાલવી જોઈએ"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> સુધી"</string>
- <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) -->
- <skip />
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"બૅટરી <xliff:g id="TIME">%1$s</xliff:g> સુધીમાં પૂરી થઈ શકે છે"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> કરતાં ઓછો સમય બાકી છે"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g> કરતાં ઓછો સમય બાકી છે (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> કરતાં વધુ સમય બાકી છે (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -511,36 +509,21 @@
<string name="media_transfer_this_device_name" msgid="2716555073132169240">"ફોન સ્પીકર"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"કનેક્ટ કરવામાં સમસ્યા આવી રહી છે. ડિવાઇસને બંધ કરીને ફરી ચાલુ કરો"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"વાયરવાળો ઑડિયો ડિવાઇસ"</string>
- <!-- no translation found for help_label (3528360748637781274) -->
- <skip />
- <!-- no translation found for storage_category (2287342585424631813) -->
- <skip />
- <!-- no translation found for shared_data_title (1017034836800864953) -->
- <skip />
- <!-- no translation found for shared_data_summary (5516326713822885652) -->
- <skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
- <!-- no translation found for blob_id_text (8680078988996308061) -->
- <skip />
- <!-- no translation found for blob_expires_text (7882727111491739331) -->
- <skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
- <!-- no translation found for accessor_info_title (8289823651512477787) -->
- <skip />
- <!-- no translation found for accessor_no_description_text (7510967452505591456) -->
- <skip />
- <!-- no translation found for accessor_expires_text (4625619273236786252) -->
- <skip />
- <!-- no translation found for delete_blob_text (2819192607255625697) -->
- <skip />
- <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) -->
- <skip />
+ <string name="help_label" msgid="3528360748637781274">"સહાય અને પ્રતિસાદ"</string>
+ <string name="storage_category" msgid="2287342585424631813">"સ્ટોરેજ"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"શેર કરેલો ડેટા"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"શેર કરેલા ડેટાને જુઓ અને તેને સંશોધિત કરો"</string>
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"આ વપરાશકર્તા માટે કોઈ શેર કરેલો ડેટા નથી."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"શેર કરેલો ડેટા મેળવવામાં ભૂલ આવી હતી. ફરી પ્રયાસ કરો."</string>
+ <string name="blob_id_text" msgid="8680078988996308061">"શેર કરેલા ડેટાનું ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
+ <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g>ના રોજ સમયસીમા સમાપ્ત થશે"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"શેર કરેલો ડેટા ડિલીટ કરતી વખતે ભૂલ આવી."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"આ શેર કરેલા ડેટા માટે કોઈ લીઝ મેળવેલી નથી. શું તમારે તેને ડિલીટ કરવો છે?"</string>
+ <string name="accessor_info_title" msgid="8289823651512477787">"ડેટા શેર કરનારી ઍપ"</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"ઍપ દ્વારા કોઈ વર્ણન આપવામાં આવ્યું નથી."</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"લીઝની સમયસીમા <xliff:g id="DATE">%s</xliff:g>ના રોજ સમાપ્ત થશે"</string>
+ <string name="delete_blob_text" msgid="2819192607255625697">"શેર કરેલા ડેટાને ડિલીટ કરો"</string>
+ <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"શું તમે ખરેખર આ શેર કરેલા ડેટાને ડિલીટ કરવા માગો છો?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"વપરાશકર્તાઓ પાસે તેઓની પોતાની ઍપ્લિકેશનો અને કન્ટેન્ટ છે"</string>
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"તમે તમારા એકાઉન્ટથી ઍપ્લિકેશનો અને સામગ્રીની અૅક્સેસને નિયંત્રિત કરી શકો છો"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"વપરાશકર્તા"</string>
@@ -560,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"પ્રોફાઇલ માહિતી"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"તમે પ્રતિબંધિત પ્રોફાઇલ બનાવી શકો તે પહેલાં, તમારે તમારી ઍપ્લિકેશનો અને વ્યક્તિગત ડેટાની સુરક્ષા માટે એક લૉક સ્ક્રીન સેટ કરવાની જરૂર પડશે."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"લૉક સેટ કરો"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 556600f..0c95313 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -512,17 +512,13 @@
<string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
<string name="storage_category" msgid="2287342585424631813">"डिवाइस की मेमोरी"</string>
<string name="shared_data_title" msgid="1017034836800864953">"शेयर किया गया डेटा"</string>
- <string name="shared_data_summary" msgid="5516326713822885652">"शेयर किए गए डेटा को देखे और उसमें बदलाव करें"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_summary" msgid="5516326713822885652">"शेयर किए गए डेटा को देखें और उसमें बदलाव करें"</string>
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"इस उपयोगकर्ता के साथ किसी तरह का डेटा शेयर नहीं किया गया है."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"शेयर किए गए इस डेटा को लाने में कोई गड़बड़ी हुई है. फिर से कोशिश करें."</string>
<string name="blob_id_text" msgid="8680078988996308061">"शेयर किए गए डेटा का आईडी: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"डेटा का ऐक्सेस <xliff:g id="DATE">%s</xliff:g> को खत्म हो जाएगा"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"शेयर किए गए डेटा को मिटाने में कोई गड़बड़ी हुई."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"शेयर किए गए इस डेटा के लिए कोई लीज़ नहीं ली गई है. क्या आप इसे मिटाना चाहते हैं?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"ऐप्लिकेशन का शेयर किया गया डेटा"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"ऐप्लिकेशन से कोई जानकारी नहीं मिली."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"लीज़ <xliff:g id="DATE">%s</xliff:g> को खत्म होगी"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"प्रोफ़ाइल की जानकारी"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"इससे पहले कि आप कोई प्रतिबंधित प्रोफ़ाइल बनाएं, आपको अपने ऐप्लिकेशन और व्यक्तिगत डेटा की सुरक्षा करने के लिए एक स्क्रीन लॉक सेट करना होगा."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करें"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 35f3d38..f1608d0d 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -514,16 +514,12 @@
<string name="storage_category" msgid="2287342585424631813">"Pohrana"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Dijeljeni podaci"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Prikaz i izmjena dijeljenih podataka"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nema dijeljenih podataka za ovog korisnika."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Došlo je do pogreške prilikom dohvaćanja dijeljenih podataka. Pokušajte ponovno."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID dijeljenih podataka: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Istječe <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Došlo je do pogreške prilikom brisanja dijeljenih podataka."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Nisu potrebna iznajmljivanja za ove dijeljene podatke. Želite li ih izbirsati?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikacije koje dijele podatke"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"U aplikaciji nije naveden opis."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Najam istječe <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -548,4 +544,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profilni podaci"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Prije izrade ograničenog profila trebate postaviti zaključavanje zaslona radi zaštite svojih aplikacija i osobnih podataka."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Postavi zaključavanje"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Prelazak na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 71fd2e6..d0fff21 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Tárhely"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Megosztott adatok"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Megosztott adatok megtekintése és módosítása"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nincsenek ehhez a felhasználóhoz tartozó megosztott adatok."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Hiba történt a megosztott adatok lekérésekor. Próbálkozzon újra."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Megosztott adat azonosítója: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Lejárat időpontja: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Hiba történt a megosztott adatok törlésekor."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Nem tartoznak hozzáférési engedélyek ezekhez a megosztott adatokhoz. Szeretné törölni?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Adatokat megosztó alkalmazások"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Nincs megadva leírás az alkalmazásnál."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"A bérlet a következő időpontban jár le: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profiladatok"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Mielőtt létrehozhatna egy korlátozott profilt, be kell állítania egy képernyőzárat, hogy megvédje alkalmazásait és személyes adatait."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Képernyőzár beállítása"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index abc03a7..a884c84 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Տարածք"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Հասանելի դարձված տվյալներ"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Դիտեք և փոփոխեք հասանելի դարձված տվյալները"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Այս օգտատիրոջ համար ընդհանուր տվյալներ չկան։"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Չհաջողվեց բեռնել ընդհանուր տվյալները։ Նորից փորձեք։"</string>
<string name="blob_id_text" msgid="8680078988996308061">"Հասանելի դարձված տվյալների ID՝ <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Ժամկետը լրանում է՝ <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Չհաջողվեց ջնջել ընդհանուր տվյալները։"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Այս ընդհանուր տվյալների համար ձեռք բերված վարձակալություններ չկան։ Հեռացնե՞լ տվյալները։"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Տվյալներով կիսվող հավելվածներ"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Հավելվածի կողմից տրամադրված նկարագրություն չկա։"</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Վարձակալության ժակետն ավարտվում է՝ <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Պրոֆիլի տեղեկություններ"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Նախքան դուք կկարողանաք ստեղծել սահմանափակ պրոֆիլ, դուք պետք է կարգավորեք էկրանի կողպումը` ձեր ծրագրերը և անձնական տվյալները պաշտպանելու համար:"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Կարգավորել կողպումը"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 27860e9..4022bab 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Penyimpanan"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Data bersama"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Lihat dan ubah data bersama"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Tidak ada data yang dibagikan untuk pengguna ini."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Terjadi kesalahan saat mengambil data yang dibagikan. Coba lagi."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID data bersama: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Berlaku sampai <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Terjadi error saat menghapus data yang dibagikan."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Tidak ada sewa yang diperoleh dari data yang dibagikan. Apakah Anda ingin menghapusnya?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikasi yang berbagi data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Tidak ada deskripsi yang disediakan oleh aplikasi."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Lease akan berakhir pada <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Info profil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Sebelum dapat membuat profil yang dibatasi, Anda perlu menyiapkan kunci layar untuk melindungi aplikasi dan data pribadi Anda."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Setel kunci"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Beralih ke <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Tamu"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index f483587..437e826 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Geymsla"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Deild gögn"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Skoða og breyta deildum gögnum"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Engin deild gögn eru fyrir þennan notanda."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Villa kom upp við að sækja deild gögn. Reyndu aftur."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Deilt gagnaauðkenni: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
- <string name="blob_expires_text" msgid="7882727111491739331">"Rennur út hinn <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="blob_expires_text" msgid="7882727111491739331">"Rennur út þann <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Villa kom upp við að eyða deildu gögnunum."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Engin leiga er fyrir þessi deildu gögn. Viltu eyða henni?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Forrit sem deila gögnum"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Forritið er ekki með neina lýsingu."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Leiga rennur út <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Upplýsingar um snið"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Áður en þú getur búið til takmarkað snið þarftu að setja upp skjálás til að vernda forritin þín og persónuleg gögn."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Velja lás"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 9e94151..2de543d 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -513,21 +513,17 @@
<string name="storage_category" msgid="2287342585424631813">"Archiviazione"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Dati condivisi"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Visualizza e modifica i dati condivisi"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nessun dato condiviso per questo utente."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Si è verificato un errore durante il recupero dei dati condivisi. Riprova."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID dati condivisi: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Scadenza: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
- <string name="accessor_info_title" msgid="8289823651512477787">"Dati delle app condivisi"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Si è verificato un errore durante l\'eliminazione dei dati condivisi."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Nessun lease acquisito per questi dati condivisi. Vuoi eliminarli?"</string>
+ <string name="accessor_info_title" msgid="8289823651512477787">"App che condividono dati"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Nessuna descrizione fornita dall\'app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Scadenza lease: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"Elimina dati condivisi"</string>
- <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Eliminare dati condivisi?"</string>
+ <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Eliminare i dati condivisi?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"Gli utenti hanno applicazioni e contenuti personali"</string>
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"Puoi limitare l\'accesso alle applicazioni e ai contenuti dal tuo account"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"Utente"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informazioni profilo"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Prima di poter creare un profilo con limitazioni, devi impostare un blocco schermo per proteggere le tue app e i tuoi dati personali."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Imposta blocco"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Passa a <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Ospite"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index e052cd7..86374f4 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -515,16 +515,12 @@
<string name="storage_category" msgid="2287342585424631813">"אחסון"</string>
<string name="shared_data_title" msgid="1017034836800864953">"נתונים משותפים"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"הצגה ושינוי של נתונים משותפים"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"אין נתונים משותפים למשתמש הזה."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"אירעה שגיאה באחזור הנתונים המשותפים. צריך לנסות שוב."</string>
<string name="blob_id_text" msgid="8680078988996308061">"מזהה נתונים משותפים: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"התוקף יפוג ב-<xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"אירעה שגיאה במחיקת הנתונים המשותפים."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"לא נרכשו חכירות (lease) לנתונים המשותפים האלו. למחוק אותם?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"אפליקציות שמשתפות נתונים"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"האפליקציה לא סיפקה תיאור."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"תוקף החכירה (lease) יפוג ב-<xliff:g id="DATE">%s</xliff:g>"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"פרטי פרופיל"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"לפני שתוכל ליצור פרופיל מוגבל, תצטרך להגדיר נעילת מסך כדי להגן על האפליקציות ועל הנתונים האישיים שלך."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"הגדרת נעילה"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 1f1eb02..ba8418b 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"ストレージ"</string>
<string name="shared_data_title" msgid="1017034836800864953">"共有データ"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"共有データの表示と変更"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"このユーザーの共有データはありません。"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"共有データの取得中にエラーが発生しました。もう一度お試しください。"</string>
<string name="blob_id_text" msgid="8680078988996308061">"共有データ ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"有効期限: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"共有データの削除中にエラーが発生しました。"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"この共有データが獲得しているリースはありません。削除してもよろしいですか?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"データ共有アプリ"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"アプリで説明は提供されていません。"</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"リースの有効期限: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"プロファイル情報"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"制限付きプロファイルを作成する場合は、アプリや個人データを保護するように画面ロックを設定しておく必要があります。"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ロックを設定"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 9d05471..da5ff9b 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"საცავი"</string>
<string name="shared_data_title" msgid="1017034836800864953">"გაზიარებული მონაცემები"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"გაზიარებული მონაცემების ნახვა და შეცვლა"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ამ მომხმარებლისთვის გაზიარებული მონაცემები არ არის."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"გაზიარებული მონაცემების მიღება ვერ მოხერხდა შეცდომის გამო. ცადეთ ხელახლა."</string>
<string name="blob_id_text" msgid="8680078988996308061">"გაზიარებულ მონაცემთა ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"ვადა ეწურება <xliff:g id="DATE">%s</xliff:g>-ში"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"გაზიარებული მონაცემების წაშლა ვერ მოხერხდა შეცდომის გამო."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ამ გაზიარებული მონაცემებისთვის იჯარა აღებული არ არის. გსურთ მისი წაშლა?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"აპები, რომლებიც მონაცემებს აზიარებენ"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"აპის მიერ აწერილობა არ არის მოწოდებული."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"დაქირავების ამოწურვის თარიღი: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ინფორმაცია პროფილზე"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"შეზღუდული პროფილის შექმნამდე, საკუთარი აპლიკაციებისა და პირადი მონაცემების დასაცავად, უნდა დაბლოკოთ ეკრანი."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"საკეტის დაყენება"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 8d2efec..e74f52b 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -512,22 +512,18 @@
<string name="help_label" msgid="3528360748637781274">"Анықтама және пікір"</string>
<string name="storage_category" msgid="2287342585424631813">"Жад"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Ортақ деректер"</string>
- <string name="shared_data_summary" msgid="5516326713822885652">"Жалпы деректерді көру және өзгерту"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
- <string name="blob_id_text" msgid="8680078988996308061">"Жалпы деректер идентификаторы: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"Ортақ деректерді көру және өзгерту"</string>
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Бұл пайдаланушы үшін ешқандай ортақ дерек жоқ."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Ортақ деректер алу кезінде қате шықты. Қайталап көріңіз."</string>
+ <string name="blob_id_text" msgid="8680078988996308061">"Ортақ деректер идентификаторы: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Аяқталу мерзімі: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
- <string name="accessor_info_title" msgid="8289823651512477787">"Жалпы деректері бар қолданба"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Ортақ деректерді жою кезінде қате шықты."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Ортақ деректер үшін ешқандай жалдау қажет емес. Оны жойғыңыз келе ме?"</string>
+ <string name="accessor_info_title" msgid="8289823651512477787">"Ортақ деректері бар қолданбалар"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Қолданба ешқандай сипаттама бермеді."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Рұқсаттың аяқталу мерзімі: <xliff:g id="DATE">%s</xliff:g>"</string>
- <string name="delete_blob_text" msgid="2819192607255625697">"Жалпы деректерді жою"</string>
- <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Осы жалпы деректерді шынымен жойғыңыз келе ме?"</string>
+ <string name="delete_blob_text" msgid="2819192607255625697">"Ортақ деректерді жою"</string>
+ <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Осы ортақ деректерді шынымен жойғыңыз келе ме?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"Пайдаланушылардың өздерінің қолданбалары мен мазмұны болады"</string>
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"Өз есептік жазбаңыздан қолданбалар мен мазмұнға қол жетімділікті шектеуіңізге болады"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"Пайдаланушы"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Профильдік ақпарат"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Шектелген профайл жасақтауға дейін қолданбалар мен жеке деректерді қорғау үшін экран бекітпесін тағайындау қажет."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Бекітпе тағайындау"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index de63a8e..c51f9a6 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -513,19 +513,15 @@
<string name="storage_category" msgid="2287342585424631813">"ទំហំផ្ទុក"</string>
<string name="shared_data_title" msgid="1017034836800864953">"ទិន្នន័យដែលបានចែករំលែក"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"មើល និងកែទិន្នន័យដែលបានចែករំលែក"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"មិនមានទិន្នន័យដែលបានចែករំលែកសម្រាប់អ្នកប្រើប្រាស់នេះទេ។"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"មានបញ្ហាក្នុងការទាញយកទិន្នន័យដែលបានចែករំលែក។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="blob_id_text" msgid="8680078988996308061">"លេខសម្គាល់ទិន្នន័យដែលបានចែករំលែក៖ <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"ផុតកំណត់នៅថ្ងៃទី <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"មានបញ្ហាក្នុងការលុបទិន្នន័យដែលបានចែករំលែក។"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"មិនមានការជួលដែលបានទទួលសម្រាប់ទិន្នន័យដែលបានចែករំលែកនេះទេ។ តើអ្នកចង់លុបទិន្នន័យនេះដែរទេ?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"កម្មវិធីដែលកំពុងចែករំលែកទិន្នន័យ"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"គ្មានការពណ៌នាដែលផ្ដល់ដោយកម្មវិធីទេ។"</string>
- <string name="accessor_expires_text" msgid="4625619273236786252">"ការជួលផុតកំណត់នៅថ្ងៃទី <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"ភតិសន្យាផុតកំណត់នៅថ្ងៃទី <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"លុបទិន្នន័យដែលបានចែករំលែក"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"តើអ្នកប្រាកដថាចង់លុបទិន្នន័យដែលបានចែករំលែកនេះដែរទេ?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"អ្នកប្រើមានកម្មវិធី និងមាតិកាផ្ទាល់របស់ពួកគេ"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ព័ត៌មានប្រវត្តិរូប"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"មុនពេលអ្នកអាចបង្កើតប្រវត្តិរូបបានដាក់កម្រិត អ្នកត្រូវរៀបចំការចាក់សោអេក្រង់ ដើម្បីការពារកម្មវិធី និងទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នក។"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"កំណត់ការចាក់សោ"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 16ade75..9e37fbc 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -519,18 +519,14 @@
<skip />
<!-- no translation found for shared_data_summary (5516326713822885652) -->
<skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ಈ ಬಳಕೆದಾರರಿಗೆ ಯಾವುದೇ ಹಂಚಿದ ಡೇಟಾ ಇಲ್ಲ."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"ಹಂಚಿದ ಡೇಟಾವನ್ನು ಪಡೆಯುವಲ್ಲಿ ದೋಷ ಕಂಡುಬಂದಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<!-- no translation found for blob_id_text (8680078988996308061) -->
<skip />
<!-- no translation found for blob_expires_text (7882727111491739331) -->
<skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"ಹಂಚಿದ ಡೇಟಾವನ್ನು ಅಳಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ಈ ಹಂಚಿದ ಡೇಟಾವನ್ನು ಗುತ್ತಿಗೆಗೆ ಪಡೆದಿಲ್ಲ. ನೀವು ಅದನ್ನು ಅಳಿಸಲು ಬಯಸುವಿರಾ?"</string>
<!-- no translation found for accessor_info_title (8289823651512477787) -->
<skip />
<!-- no translation found for accessor_no_description_text (7510967452505591456) -->
@@ -560,4 +556,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ಪ್ರೊಫೈಲ್ ಮಾಹಿತಿ"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ನೀವು ನಿರ್ಬಂಧಿತ ಪ್ರೊಫೈಲ್ ಅನ್ನು ರಚಿಸಬಹುದಾದರ ಮೊದಲು, ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ನೀವು ಪರದೆಯ ಲಾಕ್ ಹೊಂದಿಸುವ ಅಗತ್ಯವಿದೆ."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಹೊಂದಿಸಿ"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 4fc865e..cd69dd6 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -513,19 +513,15 @@
<string name="storage_category" msgid="2287342585424631813">"저장용량"</string>
<string name="shared_data_title" msgid="1017034836800864953">"공유 데이터"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"공유 데이터 보기 및 수정"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"이 사용자의 공유 데이터가 없습니다."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"공유 데이터를 가져오는 중에 오류가 발생했습니다. 다시 시도하세요."</string>
<string name="blob_id_text" msgid="8680078988996308061">"공유 데이터 ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"만료일: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"공유 데이터를 삭제하는 중에 오류가 발생했습니다."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"이 공유 데이터에서 사용 가능한 임대가 없습니다. 삭제하시겠습니까?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"데이터 공유 앱"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"앱에서 제공한 설명이 없습니다."</string>
- <string name="accessor_expires_text" msgid="4625619273236786252">"권한 만료일: <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"계약 만료일: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"공유 데이터 삭제"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"공유 데이터를 삭제하시겠습니까?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"사용자는 자신의 앱과 콘텐츠를 보유합니다."</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"프로필 정보"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"제한된 프로필을 만들기 전에 화면 잠금을 설정하여 앱과 개인 데이터를 보호해야 합니다."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"잠금 설정"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index bb6dfad..c05fd66 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Сактагыч"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Бөлүшүлгөн маалымат"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Бөлүшүлгөн маалыматты көрүп, өзгөртүү"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Бул колдонуучу үчүн бөлүшүлгөн маалымат жок."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Бөлүшүлгөн маалыматты алууда ката кетти. Кайталоо."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Бөлүшүлгөн маалыматты идентификатору: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Мөөнөтү <xliff:g id="DATE">%s</xliff:g> бүтөт"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Бөлүшүлгөн маалыматты өчүрүү учурунда ката кетти."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Бул бөлүшүлгөн маалымат үчүн ижара келишими жок. Аны жок кыласызбы?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Маалыматты бөлүшкөн колдонмолор"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Колдонмодо эч кандай сүрөттөмө берилген жок."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Ижаранын мөөнөтү <xliff:g id="DATE">%s</xliff:g> бүтөт"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Профилдин чоо-жайы"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Чектелген профайл түзөөрдөн мурун, сиз өзүңүздүн колдонмолоруңузду жана жеке маалыматтарыңызды коргош үчүн, бөгөттөө көшөгөсүн орнотушуңуз керек болот."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Бөгөт коюу"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index c39891b..58c8c39 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -232,8 +232,7 @@
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"ທີ່ຢູ່ IP ແລະ ຜອດ"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"ສະແກນລະຫັດ QR"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"ຈັບຄູ່ອຸປະກອນຜ່ານ Wi‑Fi ໂດຍການສະແກນລະຫັດ QR"</string>
- <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) -->
- <skip />
+ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ກະລຸນາເຊື່ອມຕໍ່ກັບເຄືອຂ່າຍ Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"ທາງລັດລາຍງານຂໍ້ຜິດພາດ"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"ສະແດງປຸ່ມໃນເມນູປິດເປີດເພື່ອບັນທຶກການລາຍງານຂໍ້ຜິດພາດ"</string>
@@ -432,8 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"ໜ້າຈະໃຊ້ໄດ້ຈົນຮອດປະມານ <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"ໜ້າຈະໃຊ້ໄດ້ຈົນຮອດປະມານ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"ຈົນກວ່າຈະຮອດ <xliff:g id="TIME">%1$s</xliff:g>"</string>
- <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) -->
- <skip />
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"ແບັດເຕີຣີອາດຈະໝົດພາຍໃນເວລາ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"ຍັງເຫຼືອໜ້ອຍກວ່າ <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"ຍັງເຫຼືອໜ້ອຍກວ່າ <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"ຍັງເຫຼືອຫຼາຍກວ່າ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -511,36 +509,21 @@
<string name="media_transfer_this_device_name" msgid="2716555073132169240">"ລຳໂພງໂທລະສັບ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ເກີດບັນຫາໃນການເຊື່ອມຕໍ່. ປິດອຸປະກອນແລ້ວເປີດກັບຄືນມາໃໝ່"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ອຸປະກອນສຽງແບບມີສາຍ"</string>
- <!-- no translation found for help_label (3528360748637781274) -->
- <skip />
- <!-- no translation found for storage_category (2287342585424631813) -->
- <skip />
- <!-- no translation found for shared_data_title (1017034836800864953) -->
- <skip />
- <!-- no translation found for shared_data_summary (5516326713822885652) -->
- <skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
- <!-- no translation found for blob_id_text (8680078988996308061) -->
- <skip />
- <!-- no translation found for blob_expires_text (7882727111491739331) -->
- <skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
- <!-- no translation found for accessor_info_title (8289823651512477787) -->
- <skip />
- <!-- no translation found for accessor_no_description_text (7510967452505591456) -->
- <skip />
- <!-- no translation found for accessor_expires_text (4625619273236786252) -->
- <skip />
- <!-- no translation found for delete_blob_text (2819192607255625697) -->
- <skip />
- <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) -->
- <skip />
+ <string name="help_label" msgid="3528360748637781274">"ຊ່ວຍເຫຼືອ ແລະ ຕິຊົມ"</string>
+ <string name="storage_category" msgid="2287342585424631813">"ບ່ອນເກັບຂໍ້ມູນ"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"ຂໍ້ມູນທີ່ແບ່ງປັນ"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"ເບິ່ງ ແລະ ແກ້ໄຂຂໍ້ມູນທີ່ແບ່ງປັນ"</string>
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ບໍ່ມີຂໍ້ມູນທີ່ແບ່ງປັນສຳລັບຜູ້ໃຊ້ນີ້."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"ເກີດຄວາມຜິດພາດໃນການໂຫຼດຂໍ້ມູນທີ່ແບ່ງປັນ. ກະລຸນາລອງໃໝ່."</string>
+ <string name="blob_id_text" msgid="8680078988996308061">"ID ຂໍ້ມູນທີ່ແບ່ງປັນແລ້ວ: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
+ <string name="blob_expires_text" msgid="7882727111491739331">"ໝົດອາຍຸວັນທີ <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"ເກີດຄວາມຜິດພາດໃນການລຶບຂໍ້ມູນທີ່ແບ່ງປັນ."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ບໍ່ມີການເຊົ່າທີ່ໄດ້ຮັບມາສຳລັບຂໍ້ມູນທີ່ແບ່ງປັນນີ້. ທ່ານຕ້ອງການລຶບມັນອອກບໍ່?"</string>
+ <string name="accessor_info_title" msgid="8289823651512477787">"ຂໍ້ມູນການແບ່ງປັນແອັບ"</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"ບໍ່ມີຄຳອະທິບາຍທີ່ສະໜອງໃຫ້ໂດຍແອັບ."</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"ການເຊົ່າຈະໝົດອາຍຸວັນທີ <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="delete_blob_text" msgid="2819192607255625697">"ລຶບຂໍ້ມູນທີ່ແບ່ງປັນອອກ"</string>
+ <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບຂໍ້ມູນທີ່ແບ່ງປັນແລ້ວນີ້ອອກ?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"ຜູ່ໃຊ້ມີແອັບຯ ແລະເນື້ອຫາຂອງຕົນເອງ"</string>
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"ທ່ານສາມາດຈໍາກັດການເຂົ້າເຖິງແອັບຯ ແລະເນື້ອຫາຈາກບັນຊີຂອງທ່ານໄດ້"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"ຜູ້ໃຊ້"</string>
@@ -560,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ຂໍ້ມູນໂປຣໄຟລ໌"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ກ່ອນທ່ານຈະສ້າງໂປຣໄຟລ໌ທີ່ຖືກຈຳກັດນັ້ນ, ທ່ານຈະຕ້ອງຕັ້ງຄ່າການລັອກໜ້າຈໍ ເພື່ອປ້ອງກັນແອັບຯ ແລະຂໍ້ມູນສ່ວນໂຕຂອງທ່ານກ່ອນ."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ຕັ້ງການລັອກ"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"ສະຫຼັບໄປ <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"ເພີ່ມແຂກ"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"ລຶບແຂກອອກ"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"ແຂກ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index b64f818..4591ca0 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -515,16 +515,12 @@
<string name="storage_category" msgid="2287342585424631813">"Saugykla"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Bendrinami duomenys"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Peržiūrėti ir keisti bendrinamus duomenis"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nėra jokių šio naudotojų bendrinamų duomenų."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Gaunant bandrinamus duomenis įvyko klaida. Bandykite dar kartą."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Bendrinamų duomenų ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Galiojimas baigiasi <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Ištrinant bendrintus duomenis įvyko klaida."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Šie bendrinami duomenys nenuomojami. Ar norite juos ištrinti?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Duomenis bendrinančios programos"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Programa nepateikė jokio aprašo."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Nuomos laikas baigiasi <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profilio informacija"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Prieš kuriant apribotą profilį reikės nustatyti ekrano užraktą, kad apsaugotumėte programas ir asmeninius duomenis."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Nustatyti užraktą"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index e1e0a12..c36b7f4 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -514,16 +514,12 @@
<string name="storage_category" msgid="2287342585424631813">"Krātuve"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Koplietotie dati"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Koplietoto datu skatīšana un modificēšana"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Šim lietotājam nav koplietoto datu."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Izgūstot koplietotos datus, radās kļūda. Mēģiniet vēlreiz."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Koplietotu datu ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Termiņš beigsies: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Dzēšot koplietotos datus, radās kļūda."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Šiem koplietotajiem datiem nav iegūtas atļaujas. Vai vēlaties dzēst datus?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Lietotņu koplietošanas dati"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Lietotne nav sniegusi aprakstu."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Nomas termiņš beigsies: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -548,4 +544,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profila informācija"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Lai varētu izveidot ierobežotu profilu, jums jāiestata ekrāna bloķēšana, kas aizsargās jūsu lietotni un personas datus."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Iestatīt bloķēšanu"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 5bfc30c..754c3a0 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Капацитет"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Споделени податоци"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Прегледајте и изменете ги споделените податоци"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Нема споделени податоци за корисников."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Грешка при вчитувањето на споделените податоци. Обидете се повторно."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID на споделените податоци: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Истекуваат на <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Грешка при бришењето на споделените податоци."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Нема стекнати закупи за споделениве податоци. Дали сакате да ги избришете?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Апликации што споделуваат податоци"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Апликацијата не дала опис."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Закупот истекува на <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Информации за профил"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Пред да може да создадете ограничен профил, треба да поставите заклучување на екранот за да ги заштити вашите апликации и лични податоци."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Постави заклучување"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Префрли на <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Додај гостин"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Гостин"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index fbdf682..bde3e92 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -232,8 +232,7 @@
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP വിലാസവും പോർട്ടും"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR കോഡ് സ്കാൻ ചെയ്യുക"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR കോഡ് സ്കാൻ ചെയ്ത് വൈഫൈയിലൂടെ ഉപകരണം ജോടിയാക്കുക"</string>
- <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) -->
- <skip />
+ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ഒരു വൈഫൈ നെറ്റ്വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യുക"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"ബഗ് റിപ്പോർട്ട് കുറുക്കുവഴി"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"ബഗ് റിപ്പോർട്ട് എടുക്കുന്നതിന് പവർ മെനുവിൽ ഒരു ബട്ടൺ കാണിക്കുക"</string>
@@ -432,8 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> വരെ നീണ്ടുനിൽക്കേണ്ടതാണ് (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> വരെ നീണ്ടുനിൽക്കേണ്ടതാണ്"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> വരെ"</string>
- <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) -->
- <skip />
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"<xliff:g id="TIME">%1$s</xliff:g> ആവുമ്പോഴേക്ക് ബാറ്ററി തീർന്നേക്കാം"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-ൽ കുറവ് സമയം ശേഷിക്കുന്നു"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-ൽ കുറവ് സമയം ശേഷിക്കുന്നു (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>-ൽ കൂടുതൽ സമയം ശേഷിക്കുന്നു (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -511,36 +509,21 @@
<string name="media_transfer_this_device_name" msgid="2716555073132169240">"ഫോൺ സ്പീക്കർ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"കണക്റ്റ് ചെയ്യുന്നതിൽ പ്രശ്നമുണ്ടായി. ഉപകരണം ഓഫാക്കി വീണ്ടും ഓണാക്കുക"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഓഡിയോ ഉപകരണം"</string>
- <!-- no translation found for help_label (3528360748637781274) -->
- <skip />
- <!-- no translation found for storage_category (2287342585424631813) -->
- <skip />
- <!-- no translation found for shared_data_title (1017034836800864953) -->
- <skip />
- <!-- no translation found for shared_data_summary (5516326713822885652) -->
- <skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
- <!-- no translation found for blob_id_text (8680078988996308061) -->
- <skip />
- <!-- no translation found for blob_expires_text (7882727111491739331) -->
- <skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
- <!-- no translation found for accessor_info_title (8289823651512477787) -->
- <skip />
- <!-- no translation found for accessor_no_description_text (7510967452505591456) -->
- <skip />
- <!-- no translation found for accessor_expires_text (4625619273236786252) -->
- <skip />
- <!-- no translation found for delete_blob_text (2819192607255625697) -->
- <skip />
- <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) -->
- <skip />
+ <string name="help_label" msgid="3528360748637781274">"സഹായവും ഫീഡ്ബാക്കും"</string>
+ <string name="storage_category" msgid="2287342585424631813">"സ്റ്റോറേജ്"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"പങ്കിട്ട ഡാറ്റ"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"പങ്കിട്ട ഡാറ്റ കാണുക, പരിഷ്കരിക്കുക"</string>
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ഈ ഉപയോക്താവിന്, പങ്കിട്ട ഡാറ്റയൊന്നുമില്ല."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"പങ്കിട്ട ഡാറ്റ ലഭ്യമാക്കുന്നതിൽ ഒരു പിശകുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="blob_id_text" msgid="8680078988996308061">"പങ്കിട്ട ഡാറ്റാ ഐഡി: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
+ <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g>-ന് കാലഹരണപ്പെടുന്നു"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"പങ്കിട്ട ഡാറ്റ ഇല്ലാതാക്കുന്നതിൽ എന്തോ പിശകുണ്ടായി."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"പങ്കിട്ട ഈ ഡാറ്റയ്ക്കായി ലീസുകളൊന്നും നേടിയിട്ടില്ല. അത് ഇല്ലാതാക്കണോ?"</string>
+ <string name="accessor_info_title" msgid="8289823651512477787">"ഡാറ്റ പങ്കിടുന്ന ആപ്പുകൾ"</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"ആപ്പ് വിവരണമൊന്നും നൽകിയിട്ടില്ല."</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"<xliff:g id="DATE">%s</xliff:g>-ന് ലീസ് കാലഹരണപ്പെടുന്നു"</string>
+ <string name="delete_blob_text" msgid="2819192607255625697">"പങ്കിട്ട ഡാറ്റ ഇല്ലാതാക്കുക"</string>
+ <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"പങ്കിട്ട ഈ ഡാറ്റ ഇല്ലാതാക്കണമെന്ന് തീർച്ചയാണോ?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"ഉപയോക്താക്കൾക്ക് സ്വന്തമായ അപ്ലിക്കേഷനുകളും ഉള്ളടക്കവും ഉണ്ടായിരിക്കും"</string>
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"നിങ്ങളുടെ അക്കൗണ്ടിൽ നിന്നും അപ്ലിക്കേഷനുകളിലേക്കും ഉള്ളടക്കത്തിലേക്കുമുള്ള ആക്സസ്സ് നിയന്ത്രിക്കാനാകും"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"ഉപയോക്താവ്"</string>
@@ -560,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"പ്രൊഫൈൽ വിവരം"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ഒരു നിയന്ത്രിത പ്രൊഫൈൽ സൃഷ്ടിക്കുന്നതിനുമുമ്പ്, നിങ്ങളുടെ അപ്ലിക്കേഷനുകളും വ്യക്തിഗത ഡാറ്റയും പരിരക്ഷിക്കുന്നതിന് ഒരു സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കേണ്ടതുണ്ട്."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ലോക്ക് സജ്ജീകരിക്കുക"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index debc85c..38c8b86 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -431,7 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"Ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> хүртэл барих ёстой (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"Ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> хүртэл барих ёстой"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> хүртэл"</string>
- <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Батерейн цэнэг <xliff:g id="TIME">%1$s</xliff:g> гээд дуусаж болзошгүй"</string>
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Батарейн цэнэг <xliff:g id="TIME">%1$s</xliff:g> гээд дуусаж болзошгүй"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-с бага хугацаа үлдсэн"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g>-с бага хугацаа үлдсэн (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>-с их хугацаа үлдсэн (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Хадгалах сан"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Хуваалцсан өгөгдөл"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Хуваалцсан өгөгдлийг харах, өөрчлөх"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Энэ хэрэглэгчид зориулж хуваалцсан өгөгдөл байхгүй байна."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Хуваалцсан өгөгдлийг дуудахад алдаа гарлаа. Дахин оролдоно уу."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Хуваалцсан өгөгдлийн ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Хугацаа нь <xliff:g id="DATE">%s</xliff:g>-д дуусна"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Хуваалцсан өгөгдлийг устгахад алдаа гарлаа."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Хуваалцсан энэ өгөгдлийн хувьд шаардагдах түрээс байхгүй. Та үүнийг устгамаар байна уу?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Аппуудын хуваалцсан өгөгдөл"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Аппаас ямар ч тайлбар өгөөгүй."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Түрээсийн хугацаа <xliff:g id="DATE">%s</xliff:g>-д дуусна"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Профайлын мэдээлэл"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Та хязгаарлагдсан профайл үүсгэхийн өмнө өөрийн апп-ууд болон хувийн өгөгдлийг хамгаалахын тулд дэлгэцийн түгжээг тохируулах шаардлагатай."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Түгжээг тохируулах"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index e7ae1c1..746ef57 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"स्टोरेज"</string>
<string name="shared_data_title" msgid="1017034836800864953">"शेअर केलेला डेटा"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"शेअर केलेला डेटा पहा आणि सुधारित करा"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"या वापरकर्त्यासाठी कोणताही शेअर केलेला डेटा नाही."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"शेअर केलेला डेटा मिळवताना एरर आली. पुन्हा प्रयत्न करा."</string>
<string name="blob_id_text" msgid="8680078988996308061">"शेअर केलेल्या डेटाचा आयडी: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> रोजी एक्स्पायर होईल"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"शेअर केलेला डेटा हटवताना एरर आली."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"हा शेअर केलेला डेटा कोणालाही भाड्याने दिलेला नाही. तुम्हाला तो हटवायचा आहे का?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"डेटा शेअर करणारी ॲप्स"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"अॅपद्वारे कोणतेही वर्णन पुरवलेले नाही."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"भाडेपट्टी <xliff:g id="DATE">%s</xliff:g> रोजी एक्स्पायर होईल"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"प्रोफाइल माहिती"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"तुम्ही एक प्रतिबंधित प्रोफाईल तयार करु शकण्यापूर्वी तुम्हाला तुमचे अॅप्स आणि वैयक्तिक डेटा संरक्षित करण्यासाठी एक स्क्रीन लॉक सेट करण्याची आवश्यकता राहील."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करा"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 58cbc48..5e400e3 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -513,19 +513,15 @@
<string name="storage_category" msgid="2287342585424631813">"Storan"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Data dikongsi"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Lihat dan ubah suai data dikongsi"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Tiada data dikongsi untuk pengguna ini."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Ralat telah berlaku semasa mengambil data dikongsi. Cuba lagi."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID data dikongsi: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Tamat tempoh pada <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Ralat telah berlaku semasa memadamkan data dikongsi."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Tiada pajakan yang telah diperoleh untuk data dikongsi ini. Adakah anda mahu memadamkan data ini?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Data perkongsian apl"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Tiada perihalan yang diberikan oleh apl."</string>
- <string name="accessor_expires_text" msgid="4625619273236786252">"Pajak tamat tempoh pada <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"Sewaan tamat tempoh pada <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"Padamkan data dikongsi"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Adakah anda pasti mahu memadamkan data dikongsi ini?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"Pengguna mempunyai apl dan kandungan mereka sendiri"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Maklumat profil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Sebelum anda boleh membuat profil yang terhad, anda perlu menyediakan kunci skrin untuk melindungi apl dan data peribadi anda."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Tetapkan kunci"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index bc97a9f..e6ebaf9 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"သိုလှောင်ခန်း"</string>
<string name="shared_data_title" msgid="1017034836800864953">"မျှဝေထားသော ဒေတာ"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"မျှဝေထားသောဒေတာကို ကြည့်ပြီး မွမ်းမံရန်"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ဤအသုံးပြုသူအတွက် မျှဝေထားသည့်ဒေတာများ မရှိပါ။"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"မျှဝေထားသည့် ဒေတာများကို ရယူရာတွင် အမှားအယွင်းရှိနေသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="blob_id_text" msgid="8680078988996308061">"မျှဝေထားသော ဒေတာ ID- <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> တွင် သက်တမ်းကုန်ပါမည်"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"မျှဝေထားသည့် ဒေတာများကို ဖျက်ရာတွင် အမှားအယွင်းရှိနေသည်။"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ဤမျှဝေထားသောဒေတာများအတွက် သဘောတူညီချက်များ မလိုအပ်ပါ။ ၎င်းကို သင်ဖျက်လိုပါသလား။"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"အက်ပ်များ မျှဝေသောဒေတာ"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"အက်ပ်ကပေးထားသော အကြောင်းအရာ မရှိပါ။"</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"ငှားရမ်းမှု <xliff:g id="DATE">%s</xliff:g> သက်တမ်းကုန်မည်"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ကိုယ်ရေးအချက်အလက်"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ကန့်သတ်ကိုယ်ရေးအချက်အလက်တစ်ခုကို မပြုလုပ်မီ သင်၏ အပလီကေးရှင်းများနှင့် ကိုယ်ပိုင်အချက်အလက်များကို ကာကွယ်ရန် မျက်နှာပြင်သော့ချခြင်းကို စီမံရန် လိုအပ်လိမ့်မည်"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"သော့ချရန် သတ်မှတ်ပါ"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> သို့ ပြောင်းရန်"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"ဧည့်သည်"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index cd2a426..b71f842 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -513,18 +513,14 @@
<string name="storage_category" msgid="2287342585424631813">"Lagring"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Delte data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Se og endre delte data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
- <string name="blob_id_text" msgid="8680078988996308061">"Delte data-ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Det finnes ingen delte data for denne brukeren."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Det har oppstått en feil ved henting av delte data. Prøv igjen."</string>
+ <string name="blob_id_text" msgid="8680078988996308061">"Delt data-ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Utløper <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Det har oppstått en feil ved sletting av de delte dataene."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Du har ikke skaffet en leieavtale for disse delte dataene. Vil du slette dem?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apper deler data"</string>
- <string name="accessor_no_description_text" msgid="7510967452505591456">"Apper gir ingen beskrivelse."</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"Appen gir ingen beskrivelse."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Leieperioden utløper <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"Slett delte data"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Er du sikker på at du vil slette disse delte dataene?"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profilinformasjon"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Før du kan opprette en begrenset profil, må du konfigurere skjermlåsen for å beskytte appene og de personlige dataene dine."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Angi lås"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index d7a39cc..79fd469 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -232,8 +232,7 @@
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ठेगाना र पोर्ट"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR कोड स्क्यान गर्नुहोस्"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR कोड स्क्यान गरेर Wi‑Fi प्रयोग गरी यन्त्रको जोडा बनाउनुहोस्"</string>
- <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) -->
- <skip />
+ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"कृपया कुनै Wi-Fi मा कनेक्ट गर्नुहोस्"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"बग प्रतिवेदन सर्टकट"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"बग रिपोर्ट लिनका लागि पावर मेनुमा बटन देखाउनुहोस्"</string>
@@ -432,8 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"ब्याट्री लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> सम्म"</string>
- <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) -->
- <skip />
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"ब्याट्री <xliff:g id="TIME">%1$s</xliff:g> बजेभित्र सकिन सक्छ"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> भन्दा कम समय बाँकी छ"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g> भन्दा कम समय बाँकी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> भन्दा बढी समय बाँकी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -511,36 +509,25 @@
<string name="media_transfer_this_device_name" msgid="2716555073132169240">"फोनको स्पिकर"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"जोड्ने क्रममा समस्या भयो। यन्त्रलाई निष्क्रिय पारेर फेरि सक्रिय गर्नुहोस्"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"तारयुक्त अडियो यन्त्र"</string>
- <!-- no translation found for help_label (3528360748637781274) -->
- <skip />
- <!-- no translation found for storage_category (2287342585424631813) -->
- <skip />
- <!-- no translation found for shared_data_title (1017034836800864953) -->
- <skip />
- <!-- no translation found for shared_data_summary (5516326713822885652) -->
- <skip />
+ <string name="help_label" msgid="3528360748637781274">"मद्दत र प्रतिक्रिया"</string>
+ <string name="storage_category" msgid="2287342585424631813">"भण्डारण"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"साझा डेटा"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"साझा डेटा हेर्नुहोस् र परिमार्जन गर्नुहोस्"</string>
<!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
<skip />
<!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
<skip />
- <!-- no translation found for blob_id_text (8680078988996308061) -->
- <skip />
- <!-- no translation found for blob_expires_text (7882727111491739331) -->
- <skip />
+ <string name="blob_id_text" msgid="8680078988996308061">"साझा डेटाको ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
+ <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> मा म्याद सकिन्छ"</string>
<!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
<skip />
<!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
<skip />
- <!-- no translation found for accessor_info_title (8289823651512477787) -->
- <skip />
- <!-- no translation found for accessor_no_description_text (7510967452505591456) -->
- <skip />
- <!-- no translation found for accessor_expires_text (4625619273236786252) -->
- <skip />
- <!-- no translation found for delete_blob_text (2819192607255625697) -->
- <skip />
- <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) -->
- <skip />
+ <string name="accessor_info_title" msgid="8289823651512477787">"साझा डेटा प्रयोग गर्ने अनुप्रयोगहरू"</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"यो अनुप्रयोगले कुनै विवरण प्रदान गरेको छैन।"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"लिजको म्याद <xliff:g id="DATE">%s</xliff:g> मा सकिन्छ"</string>
+ <string name="delete_blob_text" msgid="2819192607255625697">"साझा डेटा मेट्नुहोस्"</string>
+ <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"तपाईंले यो साझा डेटा मेटाउन खोज्नुभएकै हो?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"प्रयोगकर्ताहरूसँग आफ्नै अनुप्रयोगहरू र सामग्री हुन्छ"</string>
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"तपाईं आफ्नो खाताबाट अनुप्रयोगहरू र सामग्रीहरूको पहुँचलाई प्रतिबन्ध गर्न सक्नुहुन्छ"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"प्रयोगकर्ता"</string>
@@ -560,4 +547,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"प्रोफाइल जानकारी"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"निषेधयुक्त प्रोफाइल बनाउनु अघि तपाईँको अनुप्रयोग र व्यक्तिगत डेटा सुरक्षा गर्नाका लागि तपाईँले स्क्रिन लक सेटअप गर्नु पर्दछ ।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"लक सेट गर्नुहोस्"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index a8dda18..c780d6a 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Opslag"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Gedeelde gegevens"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Gedeelde gegevens bekijken en aanpassen"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Er zijn geen gedeelde gegevens voor deze gebruiker."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Er is een fout opgetreden bij het ophalen van gedeelde gegevens. Probeer het opnieuw."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID gedeelde gegevens: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Vervalt op <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Er is een fout opgetreden bij het verwijderen van de gedeelde gegevens."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Er zijn geen leases verkregen voor deze gedeelde gegevens. Wil je ze verwijderen?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps die gegevens delen"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Geen beschrijving geleverd door de app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Toegangsperiode vervalt op <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profielinfo"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Voordat je een beperkt profiel kunt maken, moet je een schermvergrendeling instellen om je apps en persoonsgegevens te beschermen."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Vergrendeling instellen"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 9d93f44..82cfbe3 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -519,18 +519,14 @@
<skip />
<!-- no translation found for shared_data_summary (5516326713822885652) -->
<skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ କୌଣସି ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ନାହିଁ।"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଫେଚ୍ କରିବା ସମୟରେ ଏକ ତ୍ରୁଟି ହୋଇଥିଲା। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<!-- no translation found for blob_id_text (8680078988996308061) -->
<skip />
<!-- no translation found for blob_expires_text (7882727111491739331) -->
<skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଡିଲିଟ୍ କରିବା ସମୟରେ ଏକ ତ୍ରୁଟି ହୋଇଥିଲା।"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ସେୟାର୍ କରାଯାଇଥିବା ଏହି ଡାଟା ପାଇଁ କୌଣସି ଲିଜ୍ ପ୍ରାପ୍ତ ହୋଇନାହିଁ। ଆପଣ ଏହା ଡିଲିଟ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି କି?"</string>
<!-- no translation found for accessor_info_title (8289823651512477787) -->
<skip />
<!-- no translation found for accessor_no_description_text (7510967452505591456) -->
@@ -560,4 +556,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ପ୍ରୋଫାଇଲ୍ ସୂଚନା"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ପ୍ରତିବନ୍ଧିତ ପ୍ରୋଫାଇଲ୍ ତିଆରି କରିବାବେଳେ, ନିଜ ଆପ୍ ଓ ବ୍ୟକ୍ତିଗତ ତଥ୍ୟର ସୁରକ୍ଷା ପାଇଁ ଏକ ସ୍କ୍ରୀନ୍ ଲକ୍ ସେଟ୍ କରନ୍ତୁ।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ଲକ୍ ସେଟ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 6ed8d1b..52ba604 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -232,8 +232,7 @@
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ਪਤਾ & ਪੋਰਟ"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR ਕੋਡ ਸਕੈਨ ਕਰੋ"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR ਕੋਡ ਸਕੈਨ ਕਰਕੇ ਵਾਈ-ਫਾਈ \'ਤੇ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
- <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) -->
- <skip />
+ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ਕਿਰਪਾ ਕਰਕੇ ਕਿਸੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ਡੀਬੱਗ, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"ਬੱਗ ਰਿਪੋਰਟ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"ਇੱਕ ਬੱਗ ਰਿਪੋਰਟ ਲੈਣ ਲਈ ਪਾਵਰ ਮੀਨੂ ਵਿੱਚ ਇੱਕ ਬਟਨ ਦਿਖਾਓ"</string>
@@ -432,8 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਚੱਲੇਗਾ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਤੱਕ ਚੱਲੇਗੀ"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> ਤੱਕ"</string>
- <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) -->
- <skip />
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"ਬੈਟਰੀ <xliff:g id="TIME">%1$s</xliff:g> ਤੱਕ ਖਤਮ ਹੋ ਸਕਦੀ ਹੈ"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ਤੋਂ ਘੱਟ ਸਮਾਂ ਬਾਕੀ"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ਤੋਂ ਘੱਟ ਸਮਾਂ ਬਾਕੀ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਤੋਂ ਵੱਧ ਸਮਾਂ ਬਾਕੀ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -511,36 +509,21 @@
<string name="media_transfer_this_device_name" msgid="2716555073132169240">"ਫ਼ੋਨ ਦਾ ਸਪੀਕਰ"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ ਆਈ। ਡੀਵਾਈਸ ਨੂੰ ਬੰਦ ਕਰਕੇ ਵਾਪਸ ਚਾਲੂ ਕਰੋ"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ਤਾਰ ਵਾਲਾ ਆਡੀਓ ਡੀਵਾਈਸ"</string>
- <!-- no translation found for help_label (3528360748637781274) -->
- <skip />
- <!-- no translation found for storage_category (2287342585424631813) -->
- <skip />
- <!-- no translation found for shared_data_title (1017034836800864953) -->
- <skip />
- <!-- no translation found for shared_data_summary (5516326713822885652) -->
- <skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
- <!-- no translation found for blob_id_text (8680078988996308061) -->
- <skip />
- <!-- no translation found for blob_expires_text (7882727111491739331) -->
- <skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
- <!-- no translation found for accessor_info_title (8289823651512477787) -->
- <skip />
- <!-- no translation found for accessor_no_description_text (7510967452505591456) -->
- <skip />
- <!-- no translation found for accessor_expires_text (4625619273236786252) -->
- <skip />
- <!-- no translation found for delete_blob_text (2819192607255625697) -->
- <skip />
- <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) -->
- <skip />
+ <string name="help_label" msgid="3528360748637781274">"ਮਦਦ ਅਤੇ ਵਿਚਾਰ"</string>
+ <string name="storage_category" msgid="2287342585424631813">"ਸਟੋਰੇਜ"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"ਸਾਂਝਾ ਕੀਤਾ ਡਾਟਾ"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"ਸਾਂਝਾ ਕੀਤੇ ਡਾਟੇ ਨੂੰ ਦੇਖੋ ਅਤੇ ਸੋਧੋ"</string>
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ਇਸ ਵਰਤੋਂਕਾਰ ਲਈ ਕੋਈ ਸਾਂਝਾ ਕੀਤਾ ਡਾਟਾ ਨਹੀਂ ਹੈ।"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"ਸਾਂਝੇ ਕੀਤੇ ਡਾਟੇ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਵੇਲੇ ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="blob_id_text" msgid="8680078988996308061">"ਸਾਂਝਾ ਕੀਤੇ ਡਾਟੇ ਦੀ ਆਈਡੀ: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
+ <string name="blob_expires_text" msgid="7882727111491739331">"ਮਿਆਦ <xliff:g id="DATE">%s</xliff:g> ਨੂੰ ਮੁੱਕ ਜਾਵੇਗੀ"</string>
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"ਸਾਂਝੇ ਕੀਤੇ ਡਾਟੇ ਨੂੰ ਮਿਟਾਉਣ ਵੇਲੇ ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ।"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ਇਸ ਸਾਂਝੇ ਕੀਤੇ ਡਾਟੇ ਲਈ ਕੋਈ ਪਟਾ ਹਾਸਲ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ। ਕੀ ਤੁਸੀਂ ਇਸਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
+ <string name="accessor_info_title" msgid="8289823651512477787">"ਡਾਟਾ ਸਾਂਝਾ ਕਰਨ ਵਾਲੀਆਂ ਐਪਾਂ"</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"ਐਪ ਵੱਲੋਂ ਕੋਈ ਵਰਣਨ ਮੁਹੱਈਆ ਨਹੀਂ ਕਰਵਾਇਆ ਗਿਆ।"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"ਲੀਜ਼ ਦੀ ਮਿਆਦ <xliff:g id="DATE">%s</xliff:g> ਨੂੰ ਮੁੱਕ ਜਾਵੇਗੀ"</string>
+ <string name="delete_blob_text" msgid="2819192607255625697">"ਸਾਂਝਾ ਕੀਤੇ ਡਾਟੇ ਨੂੰ ਮਿਟਾਓ"</string>
+ <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇਸ ਸਾਂਝਾ ਕੀਤੇ ਡਾਟੇ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"ਉਪਭੋਗਤਾਵਾਂ ਕੋਲ ਉਹਨਾਂ ਦੀਆਂ ਆਪਣੀਆਂ ਐਪਾਂ ਅਤੇ ਸਮੱਗਰੀ ਹੁੰਦੀਆਂ ਹਨ"</string>
<string name="user_add_profile_item_summary" msgid="5418602404308968028">"ਤੁਸੀਂ ਆਪਣੇ ਖਾਤੇ ਤੋਂ ਐਪਾਂ ਅਤੇ ਸਮੱਗਰੀ ਲਈ ਪਹੁੰਚ ਪ੍ਰਤਿਬੰਧ ਕਰ ਸਕਦੇ ਹੋ"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"ਵਰਤੋਂਕਾਰ"</string>
@@ -560,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ਪ੍ਰੋਫਾਈਲ ਜਾਣਕਾਰੀ"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ਇਸਤੋਂ ਪਹਿਲਾਂ ਕਿ ਤੁਸੀਂ ਇੱਕ ਪ੍ਰਤਿਬੰਧਿਤ ਪ੍ਰੋਫਾਈਲ ਬਣਾ ਸਕੋ, ਤੁਹਾਨੂੰ ਆਪਣੀਆਂ ਐਪਾਂ ਅਤੇ ਨਿੱਜੀ ਡਾਟਾ ਸੁਰੱਖਿਅਤ ਕਰਨ ਲਈ ਇੱਕ ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਅੱਪ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">" ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index cfd0d70..602e179 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -515,16 +515,12 @@
<string name="storage_category" msgid="2287342585424631813">"Pamięć"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Udostępniane dane"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Wyświetl i zmień udostępniane dane"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Brak udostępnionych danych w przypadku tego użytkownika."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Podczas pobierania udostępnionych danych wystąpił błąd. Spróbuj ponownie."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Identyfikator udostępnianych danych: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Wygasają: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Podczas usuwania udostępnionych danych wystąpił błąd."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Brak pozyskanych dzierżaw w przypadku tych udostępnionych danych. Czy chcesz je usunąć?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikacje, które udostępniają dane"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Aplikacja nie zapewnia opisu."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Dzierżawa wygasa: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informacje o profilu"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Zanim utworzysz profil z ograniczeniami, musisz skonfigurować ekran blokady, by chronić aplikacje i osobiste dane."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Ustaw blokadę"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 59f6bab..d98c9ff 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Armazenamento"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Dados compartilhados"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ver e modificar dados compartilhados"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Não há dados compartilhados para esse usuário."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Ocorreu um erro ao buscar dados compartilhados. Tente novamente."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Código dos dados compartilhados: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expira em <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Ocorreu um erro ao excluir os dados compartilhados."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Não há leases adquiridos para esses dados compartilhados. Você quer excluí-los?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps que compartilham dados"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Nenhuma descrição fornecida pelo app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"O lease expira em <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informações do perfil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Antes de criar um perfil restrito, configure um bloqueio de tela para proteger seus apps e seus dados pessoais."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index b946f7a..c12f2d7 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Armazenamento"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Dados partilhados"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ver e modificar dados partilhados"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Não existem dados partilhados para este utilizador."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Ocorreu um erro ao obter os dados partilhados. Tente novamente."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID de dados partilhados: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expira a <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Ocorreu um erro ao eliminar os dados partilhados."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Não existem alocações adquiridas para estes dados partilhados. Pretende eliminá-los?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps a partilhar dados"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Nenhuma descrição fornecida pela app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"A alocação expira a <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informação do perfil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Antes de poder criar um perfil restrito, tem de configurar um bloqueio de ecrã para proteger as suas aplicações e dados pessoais."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 59f6bab..d98c9ff 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Armazenamento"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Dados compartilhados"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ver e modificar dados compartilhados"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Não há dados compartilhados para esse usuário."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Ocorreu um erro ao buscar dados compartilhados. Tente novamente."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Código dos dados compartilhados: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expira em <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Ocorreu um erro ao excluir os dados compartilhados."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Não há leases adquiridos para esses dados compartilhados. Você quer excluí-los?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Apps que compartilham dados"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Nenhuma descrição fornecida pelo app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"O lease expira em <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informações do perfil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Antes de criar um perfil restrito, configure um bloqueio de tela para proteger seus apps e seus dados pessoais."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Definir bloqueio"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Mudar para <xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 55881b9..90ce2a9 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -514,16 +514,12 @@
<string name="storage_category" msgid="2287342585424631813">"Stocare"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Date la care se permite accesul"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Vedeți și modificați datele la care se permite accesul"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nu există date la care se permite accesul pentru acest utilizator."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"A apărut o eroare la preluarea datelor la care se permite accesul. Încercați din nou."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID-ul datelor la care se permite accesul: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Expiră pe <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"A apărut o eroare la ștergerea datelor la care se permite accesul."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Nu există închirieri pentru datele la care se permite accesul. Doriți să le ștergeți?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplicații care permit accesul la date"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Aplicația nu oferă nicio descriere."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Închirierea expiră pe <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -548,4 +544,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informații de profil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Înainte de a putea crea un profil cu permisiuni limitate, va trebui să configurați blocarea ecranului pentru a vă proteja aplicațiile și datele personale."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Configurați blocarea"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 88e94a5..71b231c 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -515,19 +515,15 @@
<string name="storage_category" msgid="2287342585424631813">"Хранилище"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Общие данные"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Просмотр и изменение общих данных"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Нет общих данных для этого пользователя."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"При получении общих данных произошла ошибка. Повторите попытку."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Идентификатор общих данных: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Срок действия истекает <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"При удалении общих данных произошла ошибка."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Нет разрешений, полученных для этих общих данных. Удалить их?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Приложения с общими данными"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Описание не предоставлено приложением."</string>
- <string name="accessor_expires_text" msgid="4625619273236786252">"Разрешение истекает <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"Разрешение действует до <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"Удалить общие данные"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Удалить общие данные?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"У пользователей есть свои приложения и контент"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Информация о профиле"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Чтобы создать профиль с ограниченным доступом, необходимо предварительно настроить блокировку экрана для защиты приложений и личных данных"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Включить блокировку"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 5aff308..d87e288 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"ගබඩාව"</string>
<string name="shared_data_title" msgid="1017034836800864953">"බෙදා ගත් දත්ත"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"බෙදා ගත් දත්ත බලා වෙනස් කරන්න"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"මෙම පරිශීලක සඳහා බෙදා ගත් දත්ත නැත."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"බෙදා ගත් දත්ත ලබා ගැනීමේ දෝෂයක් විය. නැවත උත්සාහ කරන්න."</string>
<string name="blob_id_text" msgid="8680078988996308061">"බෙදා ගත් දත්ත ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> දින කල් ඉකුත් වේ"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"බෙදා ගත් දත්ත මැකීමේ දෝෂයක් විය."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"මෙම බෙදා ගත් දත්ත සඳහා අත්පත් කර ගත් කල්බදු නැත. ඔබ එය මැකීමට කැමතිද?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"යෙදුම් බෙදා ගැනීමේ දත්ත"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"යෙදුම මගින් විස්තර කිසිවක් ලබා දී නැත."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"කල් බද්ද <xliff:g id="DATE">%s</xliff:g> දින කල් ඉකුත් වේ"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"පැතිකඩ තොරතුරු"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"සීමිත පැතිකඩක් නිර්මාණය කිරීමට කලින්. ඔබගේ යෙදුම් සහ පෞද්ගලික දත්ත ආරක්ෂා කිරීමට තිර අගුලක් සැකසිය යුතුයි."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"අගුල සකසන්න"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> වෙත මාරු වන්න"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"අමුත්තා එක් කරන්න"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"අමුත්තා ඉවත් කරන්න"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"අමුත්තා"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 05e8a3f..0e2cd84 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -515,16 +515,12 @@
<string name="storage_category" msgid="2287342585424631813">"Priestor"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Zdieľané údaje"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Zobrazenie a úprava zdieľaných údajov"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Pre tohto používateľa nie sú k dispozícii žiadne zdieľané údaje."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Pri načítavaní zdieľaných údajov sa vyskytla chyba. Skúste to znova."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Identifikátor zdieľaných údajov: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Platnosť vyprší <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Pri odstraňovaní zdieľaných údajov sa vyskytla chyba."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Pre tieto zdieľané údaje neboli získané žiadne výpožičky. Chcete ich odstrániť?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikácie zdieľajúce údaje"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Aplikácia neposkytla žiadny popis."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Platnosť prenájmu vyprší <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Informácie o profile"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Pred vytvorením obmedzeného profilu je nutné najprv nastaviť zámku obrazovky na ochranu aplikácií a osobných údajov."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastaviť uzamknutie"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 1ddf5dd..f3bba52 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -515,16 +515,12 @@
<string name="storage_category" msgid="2287342585424631813">"Shramba"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Deljeni podatki"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ogled in sprememba deljenih podatkov"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Za tega uporabnika ni nobenih deljenih podatkov."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Pri pridobivanju deljenih podatkov je prišlo do napake. Poskusite znova."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID deljenih podatkov: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Poteče dne <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Pri brisanju deljenih podatkov je prišlo do napake."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Za te deljene podatke ni pridobljen noben zakup. Ali želite podatke izbrisati?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikacije, ki si delijo podatke"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Aplikacija ni posredovala opisa."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Zakup poteče dne <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Podatki za profil"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Preden lahko ustvarite profil z omejitvami, morate nastaviti zaklepanje zaslona, da zaščitite aplikacije in osebne podatke."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Nastavi zaklepanje"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index c1469c4..2cd2393 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Hapësira ruajtëse"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Të dhënat e ndara"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Shiko dhe modifiko të dhënat e ndara"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nuk ka të dhëna të ndara për këtë përdorues."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Ndodhi një gabim gjatë marrjes së të dhënave të ndara. Provo sërish."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID-ja e të dhënave të ndara: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Skadon më <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Ndodhi një gabim gjatë fshirjes së të dhënave të ndara."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Nuk është marrë qira për këto të dhëna të ndara. Dëshiron ta fshish?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Aplikacionet që ndajnë të dhënat"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Nuk jepet asnjë përshkrim nga aplikacioni."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Qiraja skadon në <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Inform. i profilit"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Para se të mund të krijosh një profil të kufizuar, duhet të konfigurosh një kyçje të ekranit për të mbrojtur aplikacionet dhe të dhënat e tua personale."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Cakto kyçjen"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 285e2b6..102d925 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -514,16 +514,12 @@
<string name="storage_category" msgid="2287342585424631813">"Меморијски простор"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Дељени подаци"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Прегледајте и измените дељене податке"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Нема дељених података за овог корисника."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Дошло је до грешке при преузимању дељених података. Пробајте поново."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ИД дељених података: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Истиче: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Дошло је до грешке при брисању дељених података."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Нема купљених закупа за ове дељене податке. Желите ли да их избришете?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Апликације које деле податке"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"У апликацији није наведен ниједан опис."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Изнајмљивање истиче: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -548,4 +544,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Подаци о профилу"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Да бисте могли да направите ограничени профил, треба да подесите закључавање екрана да бисте заштитили апликације и личне податке."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Подеси закључавање"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index b9db69e..50297a7 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Lagring"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Delad data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Visa och ändra delad data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Den här användaren har ingen delad data."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Det gick inte att hämta delad data. Försök igen."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Id för delad data: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Upphör den <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Det gick inte att radera delad data."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Ingen lånetid har inhämtats för denna delade data. Vill du radera den?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Appar som delar data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Ingen beskrivning har tillhandahållits av appen."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Lånetiden upphör den <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profilinfo"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Innan du skapar en begränsad profil måste du konfigurera ett skärmlås för att skydda dina appar och personliga data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurera lås"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 33f2041..bfa1208 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Hifadhi"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Data iliyoshirikiwa"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Angalia na ubadilishe data iliyoshirikiwa"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Hakuna data ya mtumiaji huyu iliyoshirikiwa."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Hitilafu imetokea wakati wa kuleta data iliyoshirikiwa. Jaribu tena."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Kitambulisho cha data iliyoshirikiwa: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Muda wake utaisha<xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Hitilafu imetokea wakati wa kufuta data iliyoshirikiwa."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Hakuna ukodishaji unaopatikana wa data hii iliyoshirikiwa. Je, ungependa kuifuta?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Programu zinazoshiriki data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Hakuna maelezo yaliyotolewa na programu."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Muda wa kukodisha utaisha <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Maelezo ya wasifu"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Kabla uunde wasifu uliowekekwa vikwazo, utahitajika kuweka skrini iliyofungwa ili kulinda programu zako na data binafsi."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Weka ufunguo"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 3826e61..98bb0ca 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -520,18 +520,14 @@
<skip />
<!-- no translation found for shared_data_summary (5516326713822885652) -->
<skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"இந்தப் பயனருடன் பகிரப்பட்ட தரவு எதுவும் இல்லை."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"பகிரப்பட்ட தரவைப் பெறுவதில் பிழை. மீண்டும் முயலவும்."</string>
<!-- no translation found for blob_id_text (8680078988996308061) -->
<skip />
<!-- no translation found for blob_expires_text (7882727111491739331) -->
<skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"பகிரப்பட்ட தரவை நீக்குவதில் பிழை."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"இந்தப் பகிரப்பட்ட தரவிற்காகப் பெறப்பட்ட ஒப்பந்தங்கள் எதுவும் இல்லை. இதை நீக்க விரும்புகிறீர்களா?"</string>
<!-- no translation found for accessor_info_title (8289823651512477787) -->
<skip />
<!-- no translation found for accessor_no_description_text (7510967452505591456) -->
@@ -561,4 +557,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"சுயவிவரத் தகவல்"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"நீங்கள் வரையறுக்கப்பட்டச் சுயவிவரத்தை உருவாக்குவதற்கு முன்பு, உங்கள் ஆப்ஸ் மற்றும் தனிப்பட்ட தரவைப் பாதுகாக்கும் வகையில் நீங்கள் திரைப் பூட்டை அமைக்க வேண்டும்."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"பூட்டை அமை"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index fe18c83..a36b6a3 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -418,8 +418,7 @@
<string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ప్రొటానోమలీ (ఎరుపు-ఆకుపచ్చ రంగు)"</string>
<string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ట్రైటనోమలీ (నీలం-పసుపు రంగు)"</string>
<string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"రంగు సవరణ"</string>
- <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (1284746051652993443) -->
- <skip />
+ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"రంగుల సరి చేసే ఫీచర్తో మీరు మీ పరికరంలో రంగులో కనిపించే పద్ధతిని సర్దుబాటు చేయగలుగుతారు"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
@@ -520,18 +519,14 @@
<skip />
<!-- no translation found for shared_data_summary (5516326713822885652) -->
<skip />
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ఈ యూజర్ కోసం షేర్ చేసిన డేటా ఏదీ లేదు."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"షేర్ చేసిన డేటా పొందడంలో ఎర్రర్ ఏర్పడింది. మళ్లీ ట్రై చేయండి."</string>
<!-- no translation found for blob_id_text (8680078988996308061) -->
<skip />
<!-- no translation found for blob_expires_text (7882727111491739331) -->
<skip />
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"షేర్ చేసిన డేటాను తొలగించడంలో ఎర్రర్ ఏర్పడింది."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ఈ షేర్ చేసిన డేటాకు సేకరించబడిన లీజులు ఏవీ లేవు. దీన్ని మీరు తొలగించాలనుకుంటున్నారా?"</string>
<!-- no translation found for accessor_info_title (8289823651512477787) -->
<skip />
<!-- no translation found for accessor_no_description_text (7510967452505591456) -->
@@ -561,4 +556,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ప్రొఫైల్ సమాచారం"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"మీరు పరిమితం చేయబడిన ప్రొఫైల్ను సృష్టించడానికి ముందు, మీ అనువర్తనాలు మరియు వ్యక్తిగత డేటాను రక్షించడానికి స్క్రీన్ లాక్ను సెటప్ చేయాల్సి ఉంటుంది."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"లాక్ను సెట్ చేయి"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 31c6051..765c5dd 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -232,7 +232,7 @@
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"ที่อยู่ IP และพอร์ต"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"สแกนคิวอาร์โค้ด"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"จับคู่อุปกรณ์ผ่าน Wi‑Fi ด้วยการสแกนคิวอาร์โค้ด"</string>
- <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"โปรดเชื่อมต่อเครือข่าย Wi-Fi"</string>
+ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"โปรดเชื่อมต่อกับเครือข่าย Wi-Fi"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, แก้ไขข้อบกพร่อง, พัฒนา"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"ทางลัดรายงานข้อบกพร่อง"</string>
<string name="bugreport_in_power_summary" msgid="1885529649381831775">"แสดงปุ่มในเมนูเปิด/ปิดสำหรับการใช้รายงานข้อบกพร่อง"</string>
@@ -547,4 +547,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ข้อมูลโปรไฟล์"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ก่อนที่คุณจะสามารถสร้างโปรไฟล์ที่ถูกจำกัดได้ คุณจะต้องตั้งค่าล็อกหน้าจอเพื่อปกป้องแอปและข้อมูลส่วนตัวของคุณ"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ตั้งค่าล็อก"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a3ae082..1146619 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Storage"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Pinaghahatiang data"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Tingnan at baguhin ang pinaghahatiang data"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Walang nakabahaging data para sa user na ito."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Nagka-error sa pag-fetch ng nakabahaging data. Subukan ulit."</string>
<string name="blob_id_text" msgid="8680078988996308061">"ID ng pinaghahatiang data: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Mag-e-expire sa <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Nagka-error sa pag-delete ng nakabahaging data."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Walang nakuhang lease para sa nakabahaging data na ito. Gusto mo ba itong i-delete?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Mga app na nagbabahagi ng data"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Walang paglalarawang ibinigay ang app."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Mag-e-expire ang lease sa <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Info sa profile"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Bago ka makakalikha ng pinaghihigpitang profile, kakailanganin mong mag-set up ng screen lock upang protektahan ang iyong apps at personal na data."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Itakda ang lock"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 21f10c6..3853331 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Depolama"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Paylaşılan veri"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Paylaşılan verileri görüntüleyin ve değiştirin"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Bu kullanıcı için paylaşılan veri yok."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Paylaşılan veri alınırken hata oluştu. Tekrar deneyin."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Paylaşılan veri kimliği: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Son kullanım tarihi: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Paylaşılan veri silinirken hata oluştu."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Bu paylaşılan veri için alınmış kiralama bulunmuyor. Bunu silmek ister misiniz?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Veri paylaşan uygulamalar"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Uygulama tarafından sağlanan açıklama yok."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Kiralama süresinin bitiş zamanı: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profil bilgisi"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Kısıtlanmış bir profil oluşturabilmeniz için uygulamalarınızı ve kişisel verilerinizi korumak üzere bir ekran kilidi oluşturmanız gerekir."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Kilidi ayarla"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index f2a7492..2eeda18 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -515,16 +515,12 @@
<string name="storage_category" msgid="2287342585424631813">"Пам\'ять"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Спільні дані"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Переглянути та змінити спільні дані"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Немає спільних даних для цього користувача."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Не вдалось отримати спільні дані. Повторіть спробу."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Ідентифікатор спільних даних: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Термін дії завершується <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Не вдалося видалити спільні дані."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"У цих спільних даних немає користувачів. Видалити їх?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Додатки зі спільним доступом до даних"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Немає опису, наданого додатком."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Період оренди закінчується <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -549,4 +545,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Інформація профілю"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Перш ніж створювати обмежений профіль, потрібно налаштувати блокування екрана, щоб захистити свої програми та особисті дані."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Налаштувати блокування"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 85b3e5c..f802ebc 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"اسٹوریج"</string>
<string name="shared_data_title" msgid="1017034836800864953">"اشتراک کردہ ڈیٹا"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"اشتراک کردہ ڈیٹا میں ترمیم اور ملاحظہ کریں"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"اس صارف کے لیے کوئی اشتراک کردہ ڈیٹا نہیں ہے۔"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"اشتراک کردہ ڈیٹا بازیافت کرنے میں ایک خرابی تھی۔ دوبارہ کوشش کریں۔"</string>
<string name="blob_id_text" msgid="8680078988996308061">"اشتراک کردہ ڈیٹا کی ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"میعاد کے اختتام کی تاریخ <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"اشتراک کردہ ڈیٹا حذف کرنے میں ایک خرابی پیش آ گئی تھی۔"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"اس اشتراک کردہ ڈیٹا کے لیے کوئی لیز حاصل نہیں کی گئی ہے۔ کیا آپ اسے حذف کرنا چاہیں گے؟"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"ڈیٹا کا اشتراک کرنے والی ایپس"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"ایپ کے ذریعے کوئی بھی تفصیل فراہم نہیں کی گئی۔"</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"لیز کی میعاد <xliff:g id="DATE">%s</xliff:g> کو ختم ہونے والی ہے"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"پروفائل کی معلومات"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ایک محدود پروفائل بنانے سے پہلے، آپ کو اپنی ایپس اور ذاتی ڈیٹا کو محفوظ کرنے کیلئے ایک اسکرین لاک سیٹ اپ کرنا ہوگا۔"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"لاک سیٹ کریں"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 9578124..52fe395 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Xotira"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Umumiy maʼlumotlar"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Umumiy maʼlumotlarni ochish va oʻzgartirish"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Bu foydalanuvchining umumiy maʼlumotlari topilmadi."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Umumiy maʼlumotlarni yuklashda xatolik yuz berdi. Qayta urining."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Umumiy maʼlumotlar identifikatori: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Amal qilish muddati: <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Umumiy maʼlumotlarni oʻchirishda xatolik yuz berdi."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Bu umumiy maʼlumotlar yuzasidan kelgan soʻrov topilmadi. Oʻchirib tashlansinmi?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Umumiy maʼlumotlar bor ilovalar"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Ilova hech qanday tavsif bermagan."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Ruxsat eskirish sanasi: <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Profil haqida axborot"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Cheklangan profil yaratish uchun, shaxsiy ilovlar va ma‘lumotlarni himoyalash maqsadida avval ekran qulfini yaratish lozim."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Qulf o‘rnatish"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 4af1b4f0..eb22f7d 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Bộ nhớ"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Dữ liệu được chia sẻ"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Xem và sửa đổi dữ liệu được chia sẻ"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Không có dữ liệu được chia sẻ nào cho người dùng này."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Đã xảy ra lỗi khi tìm nạp dữ liệu được chia sẻ. Hãy thử lại."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Mã dữ liệu được chia sẻ: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Hết hạn vào <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Đã xảy ra lỗi khi xóa dữ liệu được chia sẻ."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Dữ liệu được chia sẻ này không có hợp đồng thuê nào. Bạn có muốn xóa dữ liệu này không?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Những ứng dụng chia sẻ dữ liệu"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Ứng dụng này không cung cấp thông tin mô tả nào."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Thời gian thuê kết thúc vào ngày <xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Thông tin hồ sơ"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Trước khi bạn có thể tạo tiểu sử bị hạn chế, bạn sẽ cần thiết lập một màn hình khóa để bảo vệ các ứng dụng và dữ liệu cá nhân của bạn."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Thiết lập khóa"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index d5425b2..a4727ca 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -431,7 +431,7 @@
<string name="power_discharge_by" msgid="4113180890060388350">"目前电量为 <xliff:g id="LEVEL">%2$s</xliff:g>,估计能用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"估计能用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharge_by_only_short" msgid="5883041507426914446">"直到<xliff:g id="TIME">%1$s</xliff:g>"</string>
- <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"电池电量可能在<xliff:g id="TIME">%1$s</xliff:g> 耗尽"</string>
+ <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"电池电量可能在<xliff:g id="TIME">%1$s</xliff:g> 前耗尽"</string>
<string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"剩余电池续航时间不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
<string name="power_remaining_less_than_duration" msgid="1812668275239801236">"电量剩余使用时间不到 <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"电量剩余使用时间超过 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -513,18 +513,14 @@
<string name="storage_category" msgid="2287342585424631813">"存储"</string>
<string name="shared_data_title" msgid="1017034836800864953">"共享数据"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"查看和修改共享数据"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"此用户没有共享数据。"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"提取共享数据时出错。请重试。"</string>
<string name="blob_id_text" msgid="8680078988996308061">"共享数据 ID:<xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"到期时间是 <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"删除共享数据时出错。"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"此共享数据未获得租用。要将其删除吗?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"共享数据的应用"</string>
- <string name="accessor_no_description_text" msgid="7510967452505591456">"该应用未提供任何说明。"</string>
+ <string name="accessor_no_description_text" msgid="7510967452505591456">"此应用未提供任何说明。"</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"租约到期时间是 <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"删除共享数据"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"确定要删除这些共享数据吗?"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"个人资料信息"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"您需要先设置锁定屏幕来保护您的应用和个人数据,然后才可以创建受限个人资料。"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"设置屏幕锁定方式"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 07e4070..b3f28fa 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"儲存空間"</string>
<string name="shared_data_title" msgid="1017034836800864953">"共用資料"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"查看和修改共用資料"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"此使用者未有任何共用資料。"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"擷取共用資料時發生錯誤,請再試一次"</string>
<string name="blob_id_text" msgid="8680078988996308061">"共用資料 ID:<xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"有效期至 <xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"刪除共用資料時發生錯誤。"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"此共用資料未取得任何租用,要刪除嗎?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"應用程式共用資料"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"應用程式未提供描述。"</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"租用到期日:<xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"個人檔案資料"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"建立限制存取的個人檔案前,您必須先設定上鎖畫面來保護您的應用程式和個人資料。"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"設定上鎖畫面"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index bf6265b..05d4d46 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -513,19 +513,15 @@
<string name="storage_category" msgid="2287342585424631813">"儲存空間"</string>
<string name="shared_data_title" msgid="1017034836800864953">"共用資料"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"查看及修改共用資料"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"這位使用者沒有任何共用資料。"</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"擷取共用資料時發生錯誤,請再試一次。"</string>
<string name="blob_id_text" msgid="8680078988996308061">"共用資料 ID:<xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"到期時間:<xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"刪除共用資料時發生錯誤。"</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"這項共用資料沒有任何釋出期,要刪除這項資料嗎?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"分享資料的應用程式"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"應用程式未提供任何說明。"</string>
- <string name="accessor_expires_text" msgid="4625619273236786252">"租用到期時間:<xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="accessor_expires_text" msgid="4625619273236786252">"租約到期時間:<xliff:g id="DATE">%s</xliff:g>"</string>
<string name="delete_blob_text" msgid="2819192607255625697">"刪除共用資料"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"確定要刪除這項共用資料嗎?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"使用者擁有個人專屬的應用程式和內容"</string>
@@ -547,4 +543,12 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"設定檔資訊"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"如要建立設有限制的個人資料,你必須先設定螢幕鎖定來保護你的應用程式和個人資料。"</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"設定鎖定"</string>
+ <!-- no translation found for user_switch_to_user (6975428297154968543) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (3482026122932643557) -->
+ <skip />
+ <!-- no translation found for guest_exit_guest (5908239569510734136) -->
+ <skip />
+ <!-- no translation found for guest_nickname (6332276931583337261) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 0e08053..eb4ace6 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -513,16 +513,12 @@
<string name="storage_category" msgid="2287342585424631813">"Isitoreji"</string>
<string name="shared_data_title" msgid="1017034836800864953">"Idatha eyabiwe"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Buka futhi ulungise idatha eyabiwe"</string>
- <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) -->
- <skip />
- <!-- no translation found for shared_data_query_failure_text (3489828881998773687) -->
- <skip />
+ <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Ayikho idatha eyabiwe yalo msebenzisi."</string>
+ <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Kube nephutha lokulanda idatha eyabiwe. Zama futhi."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Idatha ye-ID eyabiwe: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
<string name="blob_expires_text" msgid="7882727111491739331">"Iphelelwa yisikhathi ngo-<xliff:g id="DATE">%s</xliff:g>"</string>
- <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) -->
- <skip />
- <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) -->
- <skip />
+ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Kube nephutha ekususeni idatha eyabiwe."</string>
+ <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Akukho ukubolekwa okutholelwe le datha eyabiwe. Ungathanda ukuyisusa?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Izinhlelo zokusebenza ezabelana idatha"</string>
<string name="accessor_no_description_text" msgid="7510967452505591456">"Ayikho incazelo enikezwe yilolu hlelo lokusebenza."</string>
<string name="accessor_expires_text" msgid="4625619273236786252">"Ukuqashiswa kuphelelwa isikhathi ngo-<xliff:g id="DATE">%s</xliff:g>"</string>
@@ -547,4 +543,8 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"Ulwazi lwephrofayela"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"Ngaphambi kokuthi ungadala iphrofayela ekhawulelwe, kuzomele usethe ukukhiya isikrini ukuze uvikele izinhlelo zakho zokusebenza nedatha yakho yomuntu siqu."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"Setha ukukhiya"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"Shintshela ku-<xliff:g id="USER_NAME">%s</xliff:g>"</string>
+ <string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
+ <string name="guest_nickname" msgid="6332276931583337261">"Isihambeli"</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index cc4ee89..f6368c4 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -109,7 +109,7 @@
protected static final String CONSTRAINED_KEY = "should_constrain";
public static final int INVOCATION_TYPE_GESTURE = 1;
- public static final int INVOCATION_TYPE_ACTIVE_EDGE = 2;
+ public static final int INVOCATION_TYPE_OTHER = 2;
public static final int INVOCATION_TYPE_VOICE = 3;
public static final int INVOCATION_TYPE_QUICK_SEARCH_BAR = 4;
public static final int INVOCATION_HOME_BUTTON_LONG_PRESS = 5;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 5c66462..496456d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -125,6 +125,7 @@
// Custom options so there is no activity transition animation
ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
0 /* enterResId */, 0 /* exitResId */);
+ options.setTaskAlwaysOnTop(true);
// Post to keep the lifecycle normal
post(() -> {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index fee33dc..6a7b0da 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -1441,7 +1441,7 @@
/** Expands the clicked bubble. */
public void expandBubble(Bubble bubble) {
- if (bubble.equals(mBubbleData.getSelectedBubble())) {
+ if (bubble != null && bubble.equals(mBubbleData.getSelectedBubble())) {
// If the bubble we're supposed to expand is the selected bubble, that means the
// overflow bubble is currently expanded. Don't tell BubbleData to set this bubble as
// selected, since it already is. Just call the stack's setSelectedBubble to expand it.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java
index 0d6d137..06205c5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTaskView.java
@@ -23,8 +23,8 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.PendingIntent;
-import android.app.TaskEmbedder;
-import android.app.TaskOrganizerTaskEmbedder;
+import android.window.TaskEmbedder;
+import android.window.TaskOrganizerTaskEmbedder;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index c40e9c0..15c9dba 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -41,8 +41,8 @@
import android.util.Log;
import android.util.Size;
import android.view.SurfaceControl;
-import android.window.ITaskOrganizer;
-import android.window.IWindowContainer;
+import android.window.TaskOrganizer;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
@@ -60,7 +60,7 @@
/**
* Manages PiP tasks such as resize and offset.
*
- * This class listens on {@link ITaskOrganizer} callbacks for windowing mode change
+ * This class listens on {@link TaskOrganizer} callbacks for windowing mode change
* both to and from PiP and issues corresponding animation if applicable.
* Normally, we apply series of {@link SurfaceControl.Transaction} when the animator is running
* and files a final {@link WindowContainerTransaction} at the end of the transition.
@@ -68,7 +68,7 @@
* This class is also responsible for general resize/offset PiP operations within SysUI component,
* see also {@link com.android.systemui.pip.phone.PipMotionHelper}.
*/
-public class PipTaskOrganizer extends ITaskOrganizer.Stub {
+public class PipTaskOrganizer extends TaskOrganizer {
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
private static final int MSG_RESIZE_IMMEDIATE = 1;
@@ -182,7 +182,7 @@
};
private ActivityManager.RunningTaskInfo mTaskInfo;
- private IWindowContainer mToken;
+ private WindowContainerToken mToken;
private SurfaceControl mLeash;
private boolean mInPip;
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
@@ -234,13 +234,9 @@
* @param animationDurationMs duration in millisecond for the exiting PiP transition
*/
public void dismissPip(int animationDurationMs) {
- try {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setActivityWindowingMode(mToken, WINDOWING_MODE_FULLSCREEN);
- WindowOrganizer.applyTransaction(wct);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to apply container transaction", e);
- }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setActivityWindowingMode(mToken, WINDOWING_MODE_FULLSCREEN);
+ WindowOrganizer.applyTransaction(wct);
final Rect destinationBounds = mBoundsToRestore.remove(mToken.asBinder());
scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
TRANSITION_DIRECTION_TO_FULLSCREEN, animationDurationMs,
@@ -258,11 +254,8 @@
mTaskInfo = info;
mToken = mTaskInfo.token;
mInPip = true;
- try {
- mLeash = mToken.getLeash();
- } catch (RemoteException e) {
- throw new RuntimeException("Unable to get leash", e);
- }
+ mLeash = mToken.getLeash();
+
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
mBoundsToRestore.put(mToken.asBinder(), currentBounds);
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
@@ -290,8 +283,8 @@
*/
@Override
public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
- IWindowContainer token = info.token;
- Objects.requireNonNull(token, "Requires valid IWindowContainer");
+ WindowContainerToken token = info.token;
+ Objects.requireNonNull(token, "Requires valid WindowContainerToken");
if (token.asBinder() != mToken.asBinder()) {
Log.wtf(TAG, "Unrecognized token: " + token);
return;
@@ -502,30 +495,26 @@
+ "directly");
}
mLastReportedBounds.set(destinationBounds);
- try {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- final Rect taskBounds;
- if (direction == TRANSITION_DIRECTION_TO_FULLSCREEN) {
- // If we are animating to fullscreen, then we need to reset the override bounds
- // on the task to ensure that the task "matches" the parent's bounds, this applies
- // also to the final windowing mode, which should be reset to undefined rather than
- // fullscreen.
- taskBounds = null;
- wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED)
- .setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
- } else {
- taskBounds = destinationBounds;
- }
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- wct.scheduleFinishEnterPip(mToken, taskBounds);
- } else {
- wct.setBounds(mToken, taskBounds);
- }
- wct.setBoundsChangeTransaction(mToken, tx);
- WindowOrganizer.applyTransaction(wct);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to apply container transaction", e);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final Rect taskBounds;
+ if (direction == TRANSITION_DIRECTION_TO_FULLSCREEN) {
+ // If we are animating to fullscreen, then we need to reset the override bounds
+ // on the task to ensure that the task "matches" the parent's bounds, this applies
+ // also to the final windowing mode, which should be reset to undefined rather than
+ // fullscreen.
+ taskBounds = null;
+ wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED)
+ .setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ } else {
+ taskBounds = destinationBounds;
}
+ if (direction == TRANSITION_DIRECTION_TO_PIP) {
+ wct.scheduleFinishEnterPip(mToken, taskBounds);
+ } else {
+ wct.setBounds(mToken, taskBounds);
+ }
+ wct.setBoundsChangeTransaction(mToken, tx);
+ WindowOrganizer.applyTransaction(wct);
}
private void animateResizePip(Rect currentBounds, Rect destinationBounds,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 8a25f4d..99d6df5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -18,7 +18,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.window.WindowOrganizer.TaskOrganizer;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
@@ -234,7 +233,7 @@
mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
try {
- TaskOrganizer.registerOrganizer(mPipTaskOrganizer, WINDOWING_MODE_PINNED);
+ mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
ActivityManager.StackInfo stackInfo = activityTaskManager.getStackInfo(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stackInfo != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index c6e6da1..52c8960 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -19,7 +19,6 @@
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.window.WindowOrganizer.TaskOrganizer;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
@@ -294,7 +293,7 @@
try {
WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener);
- TaskOrganizer.registerOrganizer(mPipTaskOrganizer, WINDOWING_MODE_PINNED);
+ mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
} catch (RemoteException | UnsupportedOperationException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 66e3211..b71c4eb 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -20,7 +20,6 @@
import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.WindowOrganizer.TaskOrganizer;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -33,11 +32,12 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Slog;
+import android.window.TaskOrganizer;
+import android.window.WindowContainerToken;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
-import android.window.IWindowContainer;
import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
@@ -181,14 +181,9 @@
private boolean mPausedTargetAdjusted = false;
private boolean getSecondaryHasFocus(int displayId) {
- try {
- IWindowContainer imeSplit = TaskOrganizer.getImeTarget(displayId);
- return imeSplit != null
- && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to get IME target", e);
- }
- return false;
+ WindowContainerToken imeSplit = TaskOrganizer.getImeTarget(displayId);
+ return imeSplit != null
+ && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
}
private void updateDimTargets() {
@@ -270,10 +265,8 @@
wct.setScreenSizeDp(mSplits.mSecondary.token,
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
}
- try {
- WindowOrganizer.applyTransaction(wct);
- } catch (RemoteException e) {
- }
+
+ WindowOrganizer.applyTransaction(wct);
// Update all the adjusted-for-ime states
if (!mPaused) {
@@ -506,12 +499,8 @@
int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
final WindowContainerTransaction tct = new WindowContainerTransaction();
mSplitLayout.resizeSplits(midPos, tct);
- try {
- WindowOrganizer.applyTransaction(tct);
- } catch (RemoteException e) {
- }
- } else if (mRotateSplitLayout != null
- && mSplitLayout.mDisplayLayout.rotation()
+ WindowOrganizer.applyTransaction(tct);
+ } else if (mSplitLayout.mDisplayLayout.rotation()
== mRotateSplitLayout.mDisplayLayout.rotation()) {
mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
@@ -653,7 +642,7 @@
}
}
updateTouchable();
- WindowManagerProxy.applyContainerTransaction(wct);
+ WindowOrganizer.applyTransaction(wct);
}
void setAdjustedForIme(boolean adjustedForIme) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index a6f6741..91d638e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -22,7 +22,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.WindowOrganizer.TaskOrganizer;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
@@ -32,11 +31,11 @@
import android.view.Display;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import android.window.ITaskOrganizer;
+import android.window.TaskOrganizer;
import java.util.ArrayList;
-class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub {
+class SplitScreenTaskOrganizer extends TaskOrganizer {
private static final String TAG = "SplitScreenTaskOrganizer";
private static final boolean DEBUG = Divider.DEBUG;
@@ -56,8 +55,8 @@
}
void init(SurfaceSession session) throws RemoteException {
- TaskOrganizer.registerOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- TaskOrganizer.registerOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ registerOrganizer(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ registerOrganizer(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
try {
mPrimary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
@@ -65,9 +64,9 @@
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
mPrimarySurface = mPrimary.token.getLeash();
mSecondarySurface = mSecondary.token.getLeash();
- } catch (RemoteException e) {
+ } catch (Exception e) {
// teardown to prevent callbacks
- TaskOrganizer.unregisterOrganizer(this);
+ unregisterOrganizer();
throw e;
}
mSplitScreenSupported = true;
@@ -99,14 +98,6 @@
}
@Override
- public void onTaskAppeared(RunningTaskInfo taskInfo) {
- }
-
- @Override
- public void onTaskVanished(RunningTaskInfo taskInfo) {
- }
-
- @Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
if (taskInfo.displayId != DEFAULT_DISPLAY) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 6ed7afe..85dcbb6 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -20,7 +20,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.window.WindowOrganizer.TaskOrganizer;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -30,7 +29,8 @@
import android.util.Log;
import android.view.Display;
import android.view.WindowManagerGlobal;
-import android.window.IWindowContainer;
+import android.window.TaskOrganizer;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
@@ -112,27 +112,21 @@
static void applyResizeSplits(int position, SplitDisplayLayout splitLayout) {
WindowContainerTransaction t = new WindowContainerTransaction();
splitLayout.resizeSplits(position, t);
- try {
- WindowOrganizer.applyTransaction(t);
- } catch (RemoteException e) {
- }
+ WindowOrganizer.applyTransaction(t);
}
- private static boolean getHomeAndRecentsTasks(List<IWindowContainer> out,
- IWindowContainer parent) {
+ private static boolean getHomeAndRecentsTasks(List<WindowContainerToken> out,
+ WindowContainerToken parent) {
boolean resizable = false;
- try {
- List<ActivityManager.RunningTaskInfo> rootTasks = parent == null
- ? TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS)
- : TaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS);
- for (int i = 0, n = rootTasks.size(); i < n; ++i) {
- final ActivityManager.RunningTaskInfo ti = rootTasks.get(i);
- out.add(ti.token);
- if (ti.topActivityType == ACTIVITY_TYPE_HOME) {
- resizable = ti.isResizable();
- }
+ List<ActivityManager.RunningTaskInfo> rootTasks = parent == null
+ ? TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS)
+ : TaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS);
+ for (int i = 0, n = rootTasks.size(); i < n; ++i) {
+ final ActivityManager.RunningTaskInfo ti = rootTasks.get(i);
+ out.add(ti.token);
+ if (ti.topActivityType == ACTIVITY_TYPE_HOME) {
+ resizable = ti.isResizable();
}
- } catch (RemoteException e) {
}
return resizable;
}
@@ -142,11 +136,11 @@
* split is minimized. This actually "sticks out" of the secondary split area, but when in
* minimized mode, the secondary split gets a 'negative' crop to expose it.
*/
- static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent,
+ static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, WindowContainerToken parent,
@NonNull WindowContainerTransaction wct) {
// Resize the home/recents stacks to the larger minimized-state size
final Rect homeBounds;
- final ArrayList<IWindowContainer> homeStacks = new ArrayList<>();
+ final ArrayList<WindowContainerToken> homeStacks = new ArrayList<>();
boolean isHomeResizable = getHomeAndRecentsTasks(homeStacks, parent);
if (isHomeResizable) {
homeBounds = layout.calcMinimizedHomeStackBounds();
@@ -170,36 +164,31 @@
* @return whether the home stack is resizable
*/
static boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
- try {
- // Set launchtile first so that any stack created after
- // getAllStackInfos and before reparent (even if unlikely) are placed
- // correctly.
- TaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token);
- List<ActivityManager.RunningTaskInfo> rootTasks =
- TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */);
- WindowContainerTransaction wct = new WindowContainerTransaction();
- if (rootTasks.isEmpty()) {
- return false;
- }
- tiles.mHomeAndRecentsSurfaces.clear();
- for (int i = rootTasks.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
- if (isHomeOrRecentTask(rootTask)) {
- tiles.mHomeAndRecentsSurfaces.add(rootTask.token.getLeash());
- }
- if (rootTask.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_FULLSCREEN) {
- continue;
- }
- wct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
- }
- boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct);
- WindowOrganizer.applyTransaction(wct);
- return isHomeResizable;
- } catch (RemoteException e) {
- Log.w(TAG, "Error moving fullscreen tasks to secondary split: " + e);
+ // Set launchtile first so that any stack created after
+ // getAllStackInfos and before reparent (even if unlikely) are placed
+ // correctly.
+ TaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token);
+ List<ActivityManager.RunningTaskInfo> rootTasks =
+ TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (rootTasks.isEmpty()) {
+ return false;
}
- return false;
+ tiles.mHomeAndRecentsSurfaces.clear();
+ for (int i = rootTasks.size() - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
+ if (isHomeOrRecentTask(rootTask)) {
+ tiles.mHomeAndRecentsSurfaces.add(rootTask.token.getLeash());
+ }
+ if (rootTask.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_FULLSCREEN) {
+ continue;
+ }
+ wct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
+ }
+ boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct);
+ WindowOrganizer.applyTransaction(wct);
+ return isHomeResizable;
}
private static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
@@ -214,82 +203,70 @@
* fullscreen. {@code false} resolves the other way.
*/
static void applyDismissSplit(SplitScreenTaskOrganizer tiles, boolean dismissOrMaximize) {
- try {
- // Set launch root first so that any task created after getChildContainers and
- // before reparent (pretty unlikely) are put into fullscreen.
- TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null);
- tiles.mHomeAndRecentsSurfaces.clear();
- // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
- // plus specific APIs to clean this up.
- List<ActivityManager.RunningTaskInfo> primaryChildren =
- TaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */);
- List<ActivityManager.RunningTaskInfo> secondaryChildren =
- TaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */);
- // In some cases (eg. non-resizable is launched), system-server will leave split-screen.
- // as a result, the above will not capture any tasks; yet, we need to clean-up the
- // home task bounds.
- List<ActivityManager.RunningTaskInfo> freeHomeAndRecents =
- TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS);
- if (primaryChildren.isEmpty() && secondaryChildren.isEmpty()
- && freeHomeAndRecents.isEmpty()) {
- return;
+ // Set launch root first so that any task created after getChildContainers and
+ // before reparent (pretty unlikely) are put into fullscreen.
+ TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null);
+ tiles.mHomeAndRecentsSurfaces.clear();
+ // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
+ // plus specific APIs to clean this up.
+ List<ActivityManager.RunningTaskInfo> primaryChildren =
+ TaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */);
+ List<ActivityManager.RunningTaskInfo> secondaryChildren =
+ TaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */);
+ // In some cases (eg. non-resizable is launched), system-server will leave split-screen.
+ // as a result, the above will not capture any tasks; yet, we need to clean-up the
+ // home task bounds.
+ List<ActivityManager.RunningTaskInfo> freeHomeAndRecents =
+ TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS);
+ if (primaryChildren.isEmpty() && secondaryChildren.isEmpty()
+ && freeHomeAndRecents.isEmpty()) {
+ return;
+ }
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (dismissOrMaximize) {
+ // Dismissing, so move all primary split tasks first
+ for (int i = primaryChildren.size() - 1; i >= 0; --i) {
+ wct.reparent(primaryChildren.get(i).token, null /* parent */,
+ true /* onTop */);
}
- WindowContainerTransaction wct = new WindowContainerTransaction();
- if (dismissOrMaximize) {
- // Dismissing, so move all primary split tasks first
- for (int i = primaryChildren.size() - 1; i >= 0; --i) {
- wct.reparent(primaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
+ // Don't need to worry about home tasks because they are already in the "proper"
+ // order within the secondary split.
+ for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
+ wct.reparent(ti.token, null /* parent */, true /* onTop */);
+ if (isHomeOrRecentTask(ti)) {
+ wct.setBounds(ti.token, null);
}
- // Don't need to worry about home tasks because they are already in the "proper"
- // order within the secondary split.
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
+ }
+ } else {
+ // Maximize, so move non-home secondary split first
+ for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
+ if (isHomeOrRecentTask(secondaryChildren.get(i))) {
+ continue;
+ }
+ wct.reparent(secondaryChildren.get(i).token, null /* parent */,
+ true /* onTop */);
+ }
+ // Find and place home tasks in-between. This simulates the fact that there was
+ // nothing behind the primary split's tasks.
+ for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
+ final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
+ if (isHomeOrRecentTask(ti)) {
wct.reparent(ti.token, null /* parent */, true /* onTop */);
- if (isHomeOrRecentTask(ti)) {
- wct.setBounds(ti.token, null);
- }
- }
- } else {
- // Maximize, so move non-home secondary split first
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- if (isHomeOrRecentTask(secondaryChildren.get(i))) {
- continue;
- }
- wct.reparent(secondaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
- }
- // Find and place home tasks in-between. This simulates the fact that there was
- // nothing behind the primary split's tasks.
- for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
- final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
- if (isHomeOrRecentTask(ti)) {
- wct.reparent(ti.token, null /* parent */, true /* onTop */);
- // reset bounds too
- wct.setBounds(ti.token, null);
- }
- }
- for (int i = primaryChildren.size() - 1; i >= 0; --i) {
- wct.reparent(primaryChildren.get(i).token, null /* parent */,
- true /* onTop */);
+ // reset bounds too
+ wct.setBounds(ti.token, null);
}
}
- for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) {
- wct.setBounds(freeHomeAndRecents.get(i).token, null);
+ for (int i = primaryChildren.size() - 1; i >= 0; --i) {
+ wct.reparent(primaryChildren.get(i).token, null /* parent */,
+ true /* onTop */);
}
- // Reset focusable to true
- wct.setFocusable(tiles.mPrimary.token, true /* focusable */);
- WindowOrganizer.applyTransaction(wct);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to remove stack: " + e);
}
- }
-
- static void applyContainerTransaction(WindowContainerTransaction wct) {
- try {
- WindowOrganizer.applyTransaction(wct);
- } catch (RemoteException e) {
- Log.w(TAG, "Error setting focusability: " + e);
+ for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) {
+ wct.setBounds(freeHomeAndRecents.get(i).token, null);
}
+ // Reset focusable to true
+ wct.setFocusable(tiles.mPrimary.token, true /* focusable */);
+ WindowOrganizer.applyTransaction(wct);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index a978cad..d7322a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -39,7 +39,6 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import java.io.FileDescriptor
import java.io.PrintWriter
-import java.lang.IllegalArgumentException
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.max
@@ -74,6 +73,15 @@
@VisibleForTesting
var globalActionsSpring = DepthAnimation()
+ @VisibleForTesting
+ var brightnessMirrorSpring = DepthAnimation()
+ var brightnessMirrorVisible: Boolean = false
+ set(value) {
+ field = value
+ brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f)
+ else 0)
+ }
+
/**
* Blur radius of the wake-up animation on this frame.
*/
@@ -91,7 +99,9 @@
val updateBlurCallback = Choreographer.FrameCallback {
updateScheduled = false
- val blur = max(max(shadeSpring.radius, wakeAndUnlockBlurRadius), globalActionsSpring.radius)
+ var shadeRadius = max(shadeSpring.radius, wakeAndUnlockBlurRadius)
+ shadeRadius = (shadeRadius * (1f - brightnessMirrorSpring.ratio)).toInt()
+ val blur = max(shadeRadius, globalActionsSpring.radius)
blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur)
try {
wallpaperManager.setWallpaperZoomOut(root.windowToken,
@@ -148,6 +158,7 @@
if (isDozing) {
shadeSpring.finishIfRunning()
globalActionsSpring.finishIfRunning()
+ brightnessMirrorSpring.finishIfRunning()
}
}
}
@@ -199,6 +210,7 @@
it.increaseIndent()
it.println("shadeRadius: ${shadeSpring.radius}")
it.println("globalActionsRadius: ${globalActionsSpring.radius}")
+ it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
}
}
@@ -212,7 +224,12 @@
* Blur radius visible on the UI, in pixels.
*/
var radius = 0
- private set
+
+ /**
+ * Depth ratio of the current blur radius.
+ */
+ val ratio
+ get() = blurUtils.ratioOfBlurRadius(radius)
/**
* Radius that we're animating to.
@@ -239,7 +256,7 @@
init {
springAnimation.spring = SpringForce(0.0f)
springAnimation.spring.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
- springAnimation.spring.stiffness = SpringForce.STIFFNESS_MEDIUM
+ springAnimation.spring.stiffness = SpringForce.STIFFNESS_HIGH
springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
index 564d8bc..3f74aaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationUiAdjustment.java
@@ -38,10 +38,12 @@
public final String key;
public final List<Notification.Action> smartActions;
public final List<CharSequence> smartReplies;
+ public final boolean isConversation;
@VisibleForTesting
NotificationUiAdjustment(
- String key, List<Notification.Action> smartActions, List<CharSequence> smartReplies) {
+ String key, List<Notification.Action> smartActions, List<CharSequence> smartReplies,
+ boolean isConversation) {
this.key = key;
this.smartActions = smartActions == null
? Collections.emptyList()
@@ -49,12 +51,14 @@
this.smartReplies = smartReplies == null
? Collections.emptyList()
: smartReplies;
+ this.isConversation = isConversation;
}
public static NotificationUiAdjustment extractFromNotificationEntry(
NotificationEntry entry) {
return new NotificationUiAdjustment(
- entry.getKey(), entry.getSmartActions(), entry.getSmartReplies());
+ entry.getKey(), entry.getSmartActions(), entry.getSmartReplies(),
+ entry.getRanking().isConversation());
}
public static boolean needReinflate(
@@ -63,6 +67,9 @@
if (oldAdjustment == newAdjustment) {
return false;
}
+ if (oldAdjustment.isConversation != newAdjustment.isConversation) {
+ return true;
+ }
if (areDifferent(oldAdjustment.smartActions, newAdjustment.smartActions)) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessor.kt
deleted file mode 100644
index 6be0fff..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotificationProcessor.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification
-
-import android.app.Notification
-import android.content.pm.LauncherApps
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
-import javax.inject.Inject
-
-class ConversationNotificationProcessor @Inject constructor(
- private val launcherApps: LauncherApps
-) {
- fun processNotification(entry: NotificationEntry, recoveredBuilder: Notification.Builder) {
- val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return
- messagingStyle.conversationType =
- if (entry.ranking.channel.isImportantConversation)
- Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT
- else
- Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL
- entry.ranking.shortcutInfo?.let { shortcutInfo ->
- messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo)
- shortcutInfo.shortLabel?.let { shortLabel ->
- messagingStyle.conversationTitle = shortLabel
- }
- }
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
new file mode 100644
index 0000000..7ef1d0e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification
+
+import android.app.Notification
+import android.content.Context
+import android.content.pm.LauncherApps
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.NotificationListenerService.RankingMap
+import com.android.internal.statusbar.NotificationVisibility
+import com.android.internal.widget.ConversationLayout
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationContentView
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/** Populates additional information in conversation notifications */
+class ConversationNotificationProcessor @Inject constructor(
+ private val launcherApps: LauncherApps,
+ private val conversationNotificationManager: ConversationNotificationManager
+) {
+ fun processNotification(entry: NotificationEntry, recoveredBuilder: Notification.Builder) {
+ val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return
+ messagingStyle.conversationType =
+ if (entry.ranking.channel.isImportantConversation)
+ Notification.MessagingStyle.CONVERSATION_TYPE_IMPORTANT
+ else
+ Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL
+ entry.ranking.shortcutInfo?.let { shortcutInfo ->
+ messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo)
+ shortcutInfo.shortLabel?.let { shortLabel ->
+ messagingStyle.conversationTitle = shortLabel
+ }
+ }
+ messagingStyle.unreadMessageCount =
+ conversationNotificationManager.getUnreadCount(entry, recoveredBuilder)
+ }
+}
+
+/**
+ * Tracks state related to conversation notifications, and updates the UI of existing notifications
+ * when necessary.
+ */
+@Singleton
+class ConversationNotificationManager @Inject constructor(
+ private val notificationEntryManager: NotificationEntryManager,
+ private val context: Context
+) {
+ // Need this state to be thread safe, since it's accessed from the ui thread
+ // (NotificationEntryListener) and a bg thread (NotificationContentInflater)
+ private val states = ConcurrentHashMap<String, ConversationState>()
+
+ private var notifPanelCollapsed = true
+
+ init {
+ notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener {
+
+ override fun onNotificationRankingUpdated(rankingMap: RankingMap) {
+ fun getLayouts(view: NotificationContentView) =
+ sequenceOf(view.contractedChild, view.expandedChild, view.headsUpChild)
+ val ranking = Ranking()
+ states.keys.asSequence()
+ .mapNotNull { notificationEntryManager.getActiveNotificationUnfiltered(it) }
+ .forEach { entry ->
+ if (rankingMap.getRanking(entry.sbn.key, ranking) &&
+ ranking.isConversation) {
+ val important = ranking.channel.isImportantConversation
+ entry.row?.layouts?.asSequence()
+ ?.flatMap(::getLayouts)
+ ?.mapNotNull { it as? ConversationLayout }
+ ?.forEach { it.setIsImportantConversation(important) }
+ }
+ }
+ }
+
+ override fun onEntryInflated(entry: NotificationEntry) {
+ if (!entry.ranking.isConversation) return
+ fun updateCount(isExpanded: Boolean) {
+ if (isExpanded && !notifPanelCollapsed) {
+ resetCount(entry.key)
+ entry.row?.let(::resetBadgeUi)
+ }
+ }
+ entry.row?.setOnExpansionChangedListener(::updateCount)
+ updateCount(entry.row?.isExpanded == true)
+ }
+
+ override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry)
+
+ override fun onEntryRemoved(
+ entry: NotificationEntry,
+ visibility: NotificationVisibility?,
+ removedByUser: Boolean,
+ reason: Int
+ ) = removeTrackedEntry(entry)
+ })
+ }
+
+ fun getUnreadCount(entry: NotificationEntry, recoveredBuilder: Notification.Builder): Int =
+ states.compute(entry.key) { _, state ->
+ val newCount = state?.run {
+ val old = Notification.Builder.recoverBuilder(context, notification)
+ val increment = Notification
+ .areStyledNotificationsVisiblyDifferent(old, recoveredBuilder)
+ if (increment) unreadCount + 1 else unreadCount
+ } ?: 1
+ ConversationState(newCount, entry.sbn.notification)
+ }!!.unreadCount
+
+ fun onNotificationPanelExpandStateChanged(isCollapsed: Boolean) {
+ notifPanelCollapsed = isCollapsed
+ if (isCollapsed) return
+
+ // When the notification panel is expanded, reset the counters of any expanded
+ // conversations
+ val expanded = states
+ .asSequence()
+ .mapNotNull { (key, _) ->
+ notificationEntryManager.getActiveNotificationUnfiltered(key)
+ ?.let { entry ->
+ if (entry.row?.isExpanded == true) key to entry
+ else null
+ }
+ }
+ .toMap()
+ states.replaceAll { key, state ->
+ if (expanded.contains(key)) state.copy(unreadCount = 0)
+ else state
+ }
+ // Update UI separate from the replaceAll call, since ConcurrentHashMap may re-run the
+ // lambda if threads are in contention.
+ expanded.values.asSequence().mapNotNull { it.row }.forEach(::resetBadgeUi)
+ }
+
+ private fun resetCount(key: String) {
+ states.compute(key) { _, state -> state?.copy(unreadCount = 0) }
+ }
+
+ private fun removeTrackedEntry(entry: NotificationEntry) {
+ states.remove(entry.key)
+ }
+
+ private fun resetBadgeUi(row: ExpandableNotificationRow): Unit =
+ (row.layouts?.asSequence() ?: emptySequence())
+ .mapNotNull { layout -> layout.contractedChild as? ConversationLayout }
+ .forEach { convoLayout -> convoLayout.setUnreadCount(0) }
+
+ private data class ConversationState(val unreadCount: Int, val notification: Notification)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index b90cfa8..c9cc670 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -249,6 +249,7 @@
stats.notificationVisibility);
} catch (RemoteException e) {
// system process is dead if we're here.
+ mLogger.logRemoteExceptionOnNotificationClear(entry.getKey(), e);
}
}
}
@@ -277,6 +278,7 @@
mStatusBarService.onClearAllNotifications(userId);
} catch (RemoteException e) {
// system process is dead if we're here.
+ mLogger.logRemoteExceptionOnClearAllNotifications(e);
}
final List<NotificationEntry> entries = new ArrayList<>(getAllNotifs());
@@ -743,6 +745,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface CancellationReason {}
- public static final int REASON_NOT_CANCELED = -1;
+ static final int REASON_NOT_CANCELED = -1;
public static final int REASON_UNKNOWN = 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 8675cca..ef302f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -16,11 +16,13 @@
package com.android.systemui.statusbar.notification.collection.notifcollection
+import android.os.RemoteException
import android.service.notification.NotificationListenerService.RankingMap
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel.DEBUG
import com.android.systemui.log.LogLevel.INFO
import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.LogLevel.WTF
import com.android.systemui.log.dagger.NotificationLog
import javax.inject.Inject
@@ -92,6 +94,23 @@
buffer.log(TAG, DEBUG, { str1 = entry }, { " $str1" })
}
}
+
+ fun logRemoteExceptionOnNotificationClear(key: String, e: RemoteException) {
+ buffer.log(TAG, WTF, {
+ str1 = key
+ str2 = e.toString()
+ }, {
+ "RemoteException while attempting to clear $str1:\n$str2"
+ })
+ }
+
+ fun logRemoteExceptionOnClearAllNotifications(e: RemoteException) {
+ buffer.log(TAG, WTF, {
+ str1 = e.toString()
+ }, {
+ "RemoteException while attempting to clear all notifications:\n$str1"
+ })
+ }
}
-private const val TAG = "NotifCollection"
\ No newline at end of file
+private const val TAG = "NotifCollection"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 7deabf7..19b5f5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -107,6 +107,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;
@@ -136,7 +137,11 @@
*/
public interface LayoutListener {
void onLayout();
+ }
+ /** Listens for changes to the expansion state of this row. */
+ public interface OnExpansionChangedListener {
+ void onExpansionChanged(boolean isExpanded);
}
private StatusBarStateController mStatusbarStateController;
@@ -323,6 +328,7 @@
private boolean mWasChildInGroupWhenRemoved;
private NotificationInlineImageResolver mImageResolver;
private NotificationMediaManager mMediaManager;
+ @Nullable private OnExpansionChangedListener mExpansionChangedListener;
private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
new SystemNotificationAsyncTask();
@@ -351,6 +357,10 @@
return isSystemNotification;
}
+ public NotificationContentView[] getLayouts() {
+ return Arrays.copyOf(mLayouts, mLayouts.length);
+ }
+
@Override
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
@@ -1659,8 +1669,8 @@
}
public void showAppOpsIcons(ArraySet<Integer> activeOps) {
- if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
- mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps);
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.showAppOpsIcons(activeOps);
}
mPrivateLayout.showAppOpsIcons(activeOps);
mPublicLayout.showAppOpsIcons(activeOps);
@@ -1687,8 +1697,8 @@
private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false);
private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) {
- if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
- mChildrenContainer.getHeaderView().setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
}
mPrivateLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
@@ -2911,9 +2921,16 @@
if (mIsSummaryWithChildren) {
mChildrenContainer.onExpansionChanged();
}
+ if (mExpansionChangedListener != null) {
+ mExpansionChangedListener.onExpansionChanged(nowExpanded);
+ }
}
}
+ public void setOnExpansionChangedListener(@Nullable OnExpansionChangedListener listener) {
+ mExpansionChangedListener = listener;
+ }
+
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9b9225e..8efdc1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1468,27 +1468,27 @@
}
public void showAppOpsIcons(ArraySet<Integer> activeOps) {
- if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) {
- mContractedWrapper.getNotificationHeader().showAppOpsIcons(activeOps);
+ if (mContractedChild != null) {
+ mContractedWrapper.showAppOpsIcons(activeOps);
}
- if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) {
- mExpandedWrapper.getNotificationHeader().showAppOpsIcons(activeOps);
+ if (mExpandedChild != null) {
+ mExpandedWrapper.showAppOpsIcons(activeOps);
}
- if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) {
- mHeadsUpWrapper.getNotificationHeader().showAppOpsIcons(activeOps);
+ if (mHeadsUpChild != null) {
+ mHeadsUpWrapper.showAppOpsIcons(activeOps);
}
}
/** Sets whether the notification being displayed audibly alerted the user. */
public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) {
- if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) {
- mContractedWrapper.getNotificationHeader().setRecentlyAudiblyAlerted(audiblyAlerted);
+ if (mContractedChild != null) {
+ mContractedWrapper.setRecentlyAudiblyAlerted(audiblyAlerted);
}
- if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) {
- mExpandedWrapper.getNotificationHeader().setRecentlyAudiblyAlerted(audiblyAlerted);
+ if (mExpandedChild != null) {
+ mExpandedWrapper.setRecentlyAudiblyAlerted(audiblyAlerted);
}
- if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) {
- mHeadsUpWrapper.getNotificationHeader().setRecentlyAudiblyAlerted(audiblyAlerted);
+ if (mHeadsUpChild != null) {
+ mHeadsUpWrapper.setRecentlyAudiblyAlerted(audiblyAlerted);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index 82e5f0a..8d675f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -47,6 +47,18 @@
}
};
+ private boolean mSecondaryAnimating = false;
+ private final Runnable mSecondaryVisibilityEndRunnable = () -> {
+ mSecondaryAnimating = false;
+ // If we were on screen, become GONE to avoid touches
+ if (mSecondaryView == null) return;
+ if (getVisibility() != View.GONE
+ && mSecondaryView.getVisibility() != View.GONE
+ && !mIsSecondaryVisible) {
+ mSecondaryView.setVisibility(View.GONE);
+ }
+ };
+
public StackScrollerDecorView(Context context, AttributeSet attrs) {
super(context, attrs);
setClipChildren(false);
@@ -88,9 +100,11 @@
private void setContentVisible(boolean contentVisible, boolean animate) {
if (mContentVisible != contentVisible) {
mContentAnimating = animate;
- setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable);
mContentVisible = contentVisible;
- } if (!mContentAnimating) {
+ setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable);
+ }
+
+ if (!mContentAnimating) {
mContentVisibilityEndRunnable.run();
}
}
@@ -136,8 +150,13 @@
*/
public void setSecondaryVisible(boolean nowVisible, boolean animate) {
if (mIsSecondaryVisible != nowVisible) {
- setViewVisible(mSecondaryView, nowVisible, animate, null /* endRunnable */);
+ mSecondaryAnimating = animate;
mIsSecondaryVisible = nowVisible;
+ setViewVisible(mSecondaryView, nowVisible, animate, mSecondaryVisibilityEndRunnable);
+ }
+
+ if (!mSecondaryAnimating) {
+ mSecondaryVisibilityEndRunnable.run();
}
}
@@ -170,6 +189,12 @@
if (view == null) {
return;
}
+
+ // Make sure we're visible so animations work
+ if (view.getVisibility() != View.VISIBLE) {
+ view.setVisibility(View.VISIBLE);
+ }
+
// cancel any previous animations
view.animate().cancel();
float endValue = nowVisible ? 1.0f : 0.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 7808a4b..0c311b40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -18,6 +18,8 @@
import static com.android.systemui.statusbar.notification.TransformState.TRANSFORM_Y;
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.content.Context;
import android.util.ArraySet;
@@ -60,6 +62,11 @@
protected NotificationHeaderView mNotificationHeader;
private TextView mHeaderText;
private ImageView mWorkProfileImage;
+ private View mCameraIcon;
+ private View mMicIcon;
+ private View mOverlayIcon;
+ private View mAppOps;
+ private View mAudiblyAlertedIcon;
private boolean mIsLowPriority;
private boolean mTransformLowPriorityTitle;
@@ -107,6 +114,11 @@
mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
+ mCameraIcon = mView.findViewById(com.android.internal.R.id.camera);
+ mMicIcon = mView.findViewById(com.android.internal.R.id.mic);
+ mOverlayIcon = mView.findViewById(com.android.internal.R.id.overlay);
+ mAppOps = mView.findViewById(com.android.internal.R.id.app_ops);
+ mAudiblyAlertedIcon = mView.findViewById(com.android.internal.R.id.alerted_icon);
if (mNotificationHeader != null) {
mNotificationHeader.setShowExpandButtonAtEnd(mShowExpandButtonAtEnd);
mColor = mNotificationHeader.getOriginalIconColor();
@@ -114,8 +126,35 @@
}
private void addAppOpsOnClickListener(ExpandableNotificationRow row) {
+ View.OnClickListener listener = row.getAppOpsOnClickListener();
if (mNotificationHeader != null) {
- mNotificationHeader.setAppOpsOnClickListener(row.getAppOpsOnClickListener());
+ mNotificationHeader.setAppOpsOnClickListener(listener);
+ }
+ mAppOps.setOnClickListener(listener);
+ mCameraIcon.setOnClickListener(listener);
+ mMicIcon.setOnClickListener(listener);
+ mOverlayIcon.setOnClickListener(listener);
+ }
+
+ /**
+ * Shows or hides 'app op in use' icons based on app usage.
+ */
+ @Override
+ public void showAppOpsIcons(ArraySet<Integer> appOps) {
+ if (appOps == null) {
+ return;
+ }
+ if (mOverlayIcon != null) {
+ mOverlayIcon.setVisibility(appOps.contains(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
+ ? View.VISIBLE : View.GONE);
+ }
+ if (mCameraIcon != null) {
+ mCameraIcon.setVisibility(appOps.contains(AppOpsManager.OP_CAMERA)
+ ? View.VISIBLE : View.GONE);
+ }
+ if (mMicIcon != null) {
+ mMicIcon.setVisibility(appOps.contains(AppOpsManager.OP_RECORD_AUDIO)
+ ? View.VISIBLE : View.GONE);
}
}
@@ -184,6 +223,18 @@
mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
mHeaderText);
}
+ if (mCameraIcon != null) {
+ mTransformationHelper.addViewTransformingToSimilar(mCameraIcon);
+ }
+ if (mMicIcon != null) {
+ mTransformationHelper.addViewTransformingToSimilar(mMicIcon);
+ }
+ if (mOverlayIcon != null) {
+ mTransformationHelper.addViewTransformingToSimilar(mOverlayIcon);
+ }
+ if (mAudiblyAlertedIcon != null) {
+ mTransformationHelper.addViewTransformingToSimilar(mAudiblyAlertedIcon);
+ }
}
@Override
@@ -195,6 +246,13 @@
}
@Override
+ public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) {
+ if (mAudiblyAlertedIcon != null) {
+ mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ @Override
public NotificationHeaderView getNotificationHeader() {
return mNotificationHeader;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index e4fb2f7..fa7f282 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -29,6 +29,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.util.ArraySet;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
@@ -95,6 +96,14 @@
public void onContentUpdated(ExpandableNotificationRow row) {
}
+ /**
+ * Show a set of app opp icons in the layout.
+ *
+ * @param appOps which app ops to show
+ */
+ public void showAppOpsIcons(ArraySet<Integer> appOps) {
+ }
+
public void onReinflated() {
if (shouldClearBackgroundOnReapply()) {
mBackgroundColor = 0;
@@ -362,4 +371,10 @@
public int getExtraMeasureHeight() {
return 0;
}
+
+ /**
+ * Set the view to have recently visibly alerted.
+ */
+ public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 3d0bf3f..400e794 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -22,6 +22,7 @@
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.NotificationHeaderView;
@@ -1265,4 +1266,27 @@
mHeaderVisibleAmount = headerVisibleAmount;
mCurrentHeaderTranslation = (int) ((1.0f - headerVisibleAmount) * mTranslationForHeader);
}
+
+ /**
+ * Show a set of app opp icons in the layout.
+ *
+ * @param appOps which app ops to show
+ */
+ public void showAppOpsIcons(ArraySet<Integer> appOps) {
+ if (mNotificationHeaderWrapper != null) {
+ mNotificationHeaderWrapper.showAppOpsIcons(appOps);
+ }
+ if (mNotificationHeaderWrapperLowPriority != null) {
+ mNotificationHeaderWrapperLowPriority.showAppOpsIcons(appOps);
+ }
+ }
+
+ public void setRecentlyAudiblyAlerted(boolean audiblyAlertedRecently) {
+ if (mNotificationHeaderWrapper != null) {
+ mNotificationHeaderWrapper.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+ }
+ if (mNotificationHeaderWrapperLowPriority != null) {
+ mNotificationHeaderWrapperLowPriority.setRecentlyAudiblyAlerted(audiblyAlertedRecently);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index c05119d..d6039af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
-import android.util.ArraySet;
import android.util.Log;
import android.view.IWindowManager;
import android.view.MotionEvent;
@@ -27,8 +26,6 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.AutoHideUiElement;
-import java.util.Set;
-
import javax.inject.Inject;
/** A controller to control all auto-hide things. Also see {@link AutoHideUiElement}. */
@@ -38,8 +35,9 @@
private final IWindowManager mWindowManagerService;
private final Handler mHandler;
- private final Set<AutoHideUiElement> mElements;
+ private AutoHideUiElement mStatusBar;
+ private AutoHideUiElement mNavigationBar;
private int mDisplayId;
private boolean mAutoHideSuspended;
@@ -55,28 +53,24 @@
IWindowManager iWindowManager) {
mHandler = handler;
mWindowManagerService = iWindowManager;
- mElements = new ArraySet<>();
mDisplayId = context.getDisplayId();
}
/**
- * Adds an {@link AutoHideUiElement} whose behavior should be controlled by the
+ * Sets a {@link AutoHideUiElement} status bar that should be controlled by the
* {@link AutoHideController}.
*/
- public void addAutoHideUiElement(AutoHideUiElement element) {
- if (element != null) {
- mElements.add(element);
- }
+ public void setStatusBar(AutoHideUiElement element) {
+ mStatusBar = element;
}
/**
- * Remove an {@link AutoHideUiElement} that was previously added.
+ * Sets a {@link AutoHideUiElement} navigation bar that should be controlled by the
+ * {@link AutoHideController}.
*/
- public void removeAutoHideUiElement(AutoHideUiElement element) {
- if (element != null) {
- mElements.remove(element);
- }
+ public void setNavigationBar(AutoHideUiElement element) {
+ mNavigationBar = element;
}
private void hideTransientBars() {
@@ -86,8 +80,12 @@
Log.w(TAG, "Cannot get WindowManager");
}
- for (AutoHideUiElement element : mElements) {
- element.hide();
+ if (mStatusBar != null) {
+ mStatusBar.hide();
+ }
+
+ if (mNavigationBar != null) {
+ mNavigationBar.hide();
}
}
@@ -121,15 +119,13 @@
}
private Runnable getCheckBarModesRunnable() {
- if (mElements.isEmpty()) {
+ if (mStatusBar != null) {
+ return () -> mStatusBar.synchronizeState();
+ } else if (mNavigationBar != null) {
+ return () -> mNavigationBar.synchronizeState();
+ } else {
return null;
}
-
- return () -> {
- for (AutoHideUiElement element : mElements) {
- element.synchronizeState();
- }
- };
}
private void cancelAutoHide() {
@@ -147,8 +143,11 @@
&& event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
&& event.getX() == 0 && event.getY() == 0;
- for (AutoHideUiElement element : mElements) {
- shouldHide &= element.shouldHideOnTouch();
+ if (mStatusBar != null) {
+ shouldHide &= mStatusBar.shouldHideOnTouch();
+ }
+ if (mNavigationBar != null) {
+ shouldHide &= mNavigationBar.shouldHideOnTouch();
}
if (shouldHide) {
@@ -162,11 +161,14 @@
}
private boolean isAnyTransientBarShown() {
- for (AutoHideUiElement element : mElements) {
- if (element.isVisible()) {
- return true;
- }
+ if (mStatusBar != null && mStatusBar.isVisible()) {
+ return true;
}
+
+ if (mNavigationBar != null && mNavigationBar.isVisible()) {
+ return true;
+ }
+
return false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 31266db..6fd3bb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -1075,12 +1075,9 @@
/** Sets {@link AutoHideController} to the navigation bar. */
public void setAutoHideController(AutoHideController autoHideController) {
- if (mAutoHideController != null) {
- mAutoHideController.removeAutoHideUiElement(mAutoHideUiElement);
- }
mAutoHideController = autoHideController;
if (mAutoHideController != null) {
- mAutoHideController.addAutoHideUiElement(mAutoHideUiElement);
+ mAutoHideController.setNavigationBar(mAutoHideUiElement);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 98ba6e5..31797d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -19,6 +19,8 @@
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
+import static java.lang.Float.isNaN;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -86,6 +88,7 @@
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -238,6 +241,7 @@
private final PulseExpansionHandler mPulseExpansionHandler;
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final ConversationNotificationManager mConversationNotificationManager;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -451,7 +455,8 @@
ActivityManager activityManager, ZenModeController zenModeController,
ConfigurationController configurationController,
FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
- StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
+ StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+ ConversationNotificationManager conversationNotificationManager) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -509,6 +514,7 @@
mShadeController = shadeController;
mLockscreenUserManager = notificationLockscreenUserManager;
mEntryManager = notificationEntryManager;
+ mConversationNotificationManager = conversationNotificationManager;
mView.setBackgroundColor(Color.TRANSPARENT);
OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener();
@@ -2005,7 +2011,12 @@
@Override
protected float getOverExpansionAmount() {
- return mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */);
+ float result = mNotificationStackScroller.getCurrentOverScrollAmount(true /* top */);
+ if (isNaN(result)) {
+ Log.wtf(TAG, "OverExpansionAmount is NaN!");
+ }
+
+ return result;
}
@Override
@@ -2143,6 +2154,7 @@
super.onExpandingFinished();
mNotificationStackScroller.onExpansionStopped();
mHeadsUpManager.onExpandingFinished();
+ mConversationNotificationManager.onNotificationPanelExpandStateChanged(isFullyCollapsed());
mIsExpanding = false;
if (isFullyCollapsed()) {
DejankUtils.postAfterTraversal(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 83cc4e3..f7d403f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static java.lang.Float.isNaN;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -638,6 +640,9 @@
}
public void setExpandedHeightInternal(float h) {
+ if (isNaN(h)) {
+ Log.wtf(TAG, "ExpandedHeight set to NaN");
+ }
if (mExpandLatencyTracking && h != 0f) {
DejankUtils.postAfterTraversal(
() -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
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 90e0452..f0cce46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -176,6 +176,7 @@
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
@@ -589,6 +590,7 @@
private ActivityLaunchAnimator mActivityLaunchAnimator;
protected StatusBarNotificationPresenter mPresenter;
private NotificationActivityStarter mNotificationActivityStarter;
+ private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
private final BubbleController mBubbleController;
private final BubbleController.BubbleExpandListener mBubbleExpandListener;
@@ -679,6 +681,7 @@
PhoneStatusBarPolicy phoneStatusBarPolicy,
KeyguardIndicationController keyguardIndicationController,
DismissCallbackRegistry dismissCallbackRegistry,
+ Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
super(context);
mNotificationsController = notificationsController;
@@ -735,6 +738,7 @@
mScreenPinningRequest = screenPinningRequest;
mDozeScrimController = dozeScrimController;
mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
+ mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy;
mVolumeComponent = volumeComponent;
mCommandQueue = commandQueue;
mRecentsOptional = recentsOptional;
@@ -1073,7 +1077,7 @@
}
});
- mAutoHideController.addAutoHideUiElement(new AutoHideUiElement() {
+ mAutoHideController.setStatusBar(new AutoHideUiElement() {
@Override
public void synchronizeState() {
checkBarModes();
@@ -1135,6 +1139,7 @@
mBrightnessMirrorController = new BrightnessMirrorController(
mNotificationShadeWindowView,
mNotificationPanelViewController,
+ mNotificationShadeDepthControllerLazy.get(),
(visible) -> {
mBrightnessMirrorVisible = visible;
updateScrimController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index bbc7e7a..b81a519 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -51,6 +51,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
@@ -197,6 +198,7 @@
UserInfoControllerImpl userInfoControllerImpl,
PhoneStatusBarPolicy phoneStatusBarPolicy,
KeyguardIndicationController keyguardIndicationController,
+ Lazy<NotificationShadeDepthController> notificationShadeDepthController,
DismissCallbackRegistry dismissCallbackRegistry,
StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
return new StatusBar(
@@ -276,6 +278,7 @@
phoneStatusBarPolicy,
keyguardIndicationController,
dismissCallbackRegistry,
+ notificationShadeDepthController,
statusBarTouchableRegionManager);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index d62da10..78111fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -24,6 +24,7 @@
import android.widget.FrameLayout;
import com.android.systemui.R;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -39,16 +40,19 @@
private final NotificationShadeWindowView mStatusBarWindow;
private final Consumer<Boolean> mVisibilityCallback;
private final NotificationPanelViewController mNotificationPanel;
+ private final NotificationShadeDepthController mDepthController;
private final ArraySet<BrightnessMirrorListener> mBrightnessMirrorListeners = new ArraySet<>();
private final int[] mInt2Cache = new int[2];
private View mBrightnessMirror;
public BrightnessMirrorController(NotificationShadeWindowView statusBarWindow,
NotificationPanelViewController notificationPanelViewController,
+ NotificationShadeDepthController notificationShadeDepthController,
@NonNull Consumer<Boolean> visibilityCallback) {
mStatusBarWindow = statusBarWindow;
mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror);
mNotificationPanel = notificationPanelViewController;
+ mDepthController = notificationShadeDepthController;
mNotificationPanel.setPanelAlphaEndAction(() -> {
mBrightnessMirror.setVisibility(View.INVISIBLE);
});
@@ -59,11 +63,13 @@
mBrightnessMirror.setVisibility(View.VISIBLE);
mVisibilityCallback.accept(true);
mNotificationPanel.setPanelAlpha(0, true /* animate */);
+ mDepthController.setBrightnessMirrorVisible(true);
}
public void hideMirror() {
mVisibilityCallback.accept(false);
mNotificationPanel.setPanelAlpha(255, true /* animate */);
+ mDepthController.setBrightnessMirrorVisible(false);
}
public void setLocation(View original) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 956bfd0..1e3636b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -45,7 +45,6 @@
import org.mockito.Mockito.doThrow
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
-import java.lang.IllegalArgumentException
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
@@ -64,6 +63,7 @@
@Mock private lateinit var viewRootImpl: ViewRootImpl
@Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation
+ @Mock private lateinit var brightnessSpring: NotificationShadeDepthController.DepthAnimation
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
private lateinit var statusBarStateListener: StatusBarStateController.StateListener
@@ -83,6 +83,7 @@
keyguardStateController, choreographer, wallpaperManager,
notificationShadeWindowController, dumpManager)
notificationShadeDepthController.shadeSpring = shadeSpring
+ notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring
notificationShadeDepthController.globalActionsSpring = globalActionsSpring
notificationShadeDepthController.root = root
@@ -134,6 +135,30 @@
verify(wallpaperManager).setWallpaperZoomOut(any(), anyFloat())
}
+ @Test
+ fun brightnessMirrorVisible_whenVisible() {
+ notificationShadeDepthController.brightnessMirrorVisible = true
+ verify(brightnessSpring).animateTo(eq(maxBlur), any())
+ }
+
+ @Test
+ fun brightnessMirrorVisible_whenHidden() {
+ notificationShadeDepthController.brightnessMirrorVisible = false
+ verify(brightnessSpring).animateTo(eq(0), any())
+ }
+
+ @Test
+ fun brightnessMirror_hidesShadeBlur() {
+ // Brightness mirror is fully visible
+ `when`(brightnessSpring.ratio).thenReturn(1f)
+ // And shade is blurred
+ `when`(shadeSpring.radius).thenReturn(maxBlur)
+
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(notificationShadeWindowController).setBackgroundBlurRadius(0)
+ verify(blurUtils).applyBlur(safeEq(viewRootImpl), eq(0))
+ }
+
private fun <T : Any> safeEq(value: T): T {
return eq(value) ?: value
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
index d00be56..3c9c9cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
@@ -188,6 +188,30 @@
.isFalse();
}
+ @Test
+ public void needReinflate_bothConversation() {
+ assertThat(NotificationUiAdjustment.needReinflate(
+ createUiAdjustmentForConversation("first", true),
+ createUiAdjustmentForConversation("first", true)))
+ .isFalse();
+ }
+
+ @Test
+ public void needReinflate_neitherConversation() {
+ assertThat(NotificationUiAdjustment.needReinflate(
+ createUiAdjustmentForConversation("first", false),
+ createUiAdjustmentForConversation("first", false)))
+ .isFalse();
+ }
+
+ @Test
+ public void needReinflate_differentIsConversation() {
+ assertThat(NotificationUiAdjustment.needReinflate(
+ createUiAdjustmentForConversation("first", false),
+ createUiAdjustmentForConversation("first", true)))
+ .isTrue();
+ }
+
private Notification.Action.Builder createActionBuilder(
String title, int drawableRes, PendingIntent pendingIntent) {
return new Notification.Action.Builder(
@@ -200,11 +224,16 @@
private NotificationUiAdjustment createUiAdjustmentFromSmartActions(
String key, List<Notification.Action> actions) {
- return new NotificationUiAdjustment(key, actions, null);
+ return new NotificationUiAdjustment(key, actions, null, false);
}
private NotificationUiAdjustment createUiAdjustmentFromSmartReplies(
String key, CharSequence[] replies) {
- return new NotificationUiAdjustment(key, null, Arrays.asList(replies));
+ return new NotificationUiAdjustment(key, null, Arrays.asList(replies), false);
+ }
+
+ private NotificationUiAdjustment createUiAdjustmentForConversation(
+ String key, boolean isConversation) {
+ return new NotificationUiAdjustment(key, null, null, isConversation);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index c356e0d..cb37920 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -229,22 +229,19 @@
@Test
public void testShowAppOpsIcons_header() {
- NotificationHeaderView mockHeader = mock(NotificationHeaderView.class);
-
NotificationContentView publicLayout = mock(NotificationContentView.class);
mGroupRow.setPublicLayout(publicLayout);
NotificationContentView privateLayout = mock(NotificationContentView.class);
mGroupRow.setPrivateLayout(privateLayout);
NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
when(mockContainer.getNotificationChildCount()).thenReturn(1);
- when(mockContainer.getHeaderView()).thenReturn(mockHeader);
mGroupRow.setChildrenContainer(mockContainer);
ArraySet<Integer> ops = new ArraySet<>();
ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS);
mGroupRow.showAppOpsIcons(ops);
- verify(mockHeader, times(1)).showAppOpsIcons(ops);
+ verify(mockContainer, times(1)).showAppOpsIcons(ops);
verify(privateLayout, times(1)).showAppOpsIcons(ops);
verify(publicLayout, times(1)).showAppOpsIcons(ops);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index 84c6513..0f26898 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -76,14 +76,14 @@
@Test
@UiThreadTest
public void testShowAppOpsIcons() {
- NotificationHeaderView mockContracted = mock(NotificationHeaderView.class);
- when(mockContracted.findViewById(com.android.internal.R.id.notification_header))
+ View mockContracted = mock(View.class);
+ when(mockContracted.findViewById(com.android.internal.R.id.mic))
.thenReturn(mockContracted);
- NotificationHeaderView mockExpanded = mock(NotificationHeaderView.class);
- when(mockExpanded.findViewById(com.android.internal.R.id.notification_header))
+ View mockExpanded = mock(View.class);
+ when(mockExpanded.findViewById(com.android.internal.R.id.mic))
.thenReturn(mockExpanded);
- NotificationHeaderView mockHeadsUp = mock(NotificationHeaderView.class);
- when(mockHeadsUp.findViewById(com.android.internal.R.id.notification_header))
+ View mockHeadsUp = mock(View.class);
+ when(mockHeadsUp.findViewById(com.android.internal.R.id.mic))
.thenReturn(mockHeadsUp);
mView.setContractedChild(mockContracted);
@@ -91,11 +91,11 @@
mView.setHeadsUpChild(mockHeadsUp);
ArraySet<Integer> ops = new ArraySet<>();
- ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS);
+ ops.add(AppOpsManager.OP_RECORD_AUDIO);
mView.showAppOpsIcons(ops);
- verify(mockContracted, times(1)).showAppOpsIcons(ops);
- verify(mockExpanded, times(1)).showAppOpsIcons(ops);
- verify(mockHeadsUp, times(1)).showAppOpsIcons(any());
+ verify(mockContracted, times(1)).setVisibility(View.VISIBLE);
+ verify(mockExpanded, times(1)).setVisibility(View.VISIBLE);
+ verify(mockHeadsUp, times(1)).setVisibility(View.VISIBLE);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 13bf38c..4b09aa6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -64,6 +64,7 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -169,6 +170,8 @@
private ZenModeController mZenModeController;
@Mock
private ConfigurationController mConfigurationController;
+ @Mock
+ private ConversationNotificationManager mConversationNotificationManager;
private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -223,7 +226,8 @@
mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController,
- mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager);
+ mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
+ mConversationNotificationManager);
mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager,
mNotificationShelf, mNotificationAreaController, mScrimController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 679ac22..b905bdd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -102,6 +102,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.RemoteInputController;
@@ -249,6 +250,7 @@
@Mock private ExtensionController mExtensionController;
@Mock private UserInfoControllerImpl mUserInfoControllerImpl;
@Mock private PhoneStatusBarPolicy mPhoneStatusBarPolicy;
+ @Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private InitController mInitController = new InitController();
@@ -404,6 +406,7 @@
mPhoneStatusBarPolicy,
mKeyguardIndicationController,
mDismissCallbackRegistry,
+ mNotificationShadeDepthControllerLazy,
mStatusBarTouchableRegionManager);
when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 052026c..5faed43 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -126,6 +126,7 @@
"android.hardware.rebootescrow-java",
"android.hardware.soundtrigger-V2.3-java",
"android.hidl.manager-V1.2-java",
+ "capture_state_listener-aidl-java",
"dnsresolver_aidl_interface-V2-java",
"netd_event_listener_interface-java",
"overlayable_policy_aidl-java",
diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
index a6811e3..ea607cb 100644
--- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java
@@ -35,6 +35,8 @@
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
@@ -50,12 +52,19 @@
final class CarUserSwitchingDialog extends UserSwitchingDialog {
private static final String TAG = "ActivityManagerCarUserSwitchingDialog";
+ private View mView;
public CarUserSwitchingDialog(ActivityManagerService service, Context context, UserInfo oldUser,
UserInfo newUser, boolean aboveSystem, String switchingFromSystemUserMessage,
String switchingToSystemUserMessage) {
super(service, context, oldUser, newUser, aboveSystem, switchingFromSystemUserMessage,
switchingToSystemUserMessage);
+
+ // {@link UserSwitchingDialog} uses {@link WindowManager.LayoutParams.TYPE_SYSTEM_ERROR}
+ // when trying to show dialog above system. That window type has been deprecated and since
+ // this is a system dialog, hence, it makes sense to put this in System Dialog Window.
+ // This window also automatically shows status bar.
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
}
@Override
@@ -65,7 +74,7 @@
Resources res = getContext().getResources();
// Custom view due to alignment and font size requirements
getContext().setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog);
- View view = LayoutInflater.from(getContext()).inflate(
+ mView = LayoutInflater.from(getContext()).inflate(
R.layout.car_user_switching_dialog,
null);
@@ -75,11 +84,11 @@
if (bitmap != null) {
CircleFramedDrawable drawable = CircleFramedDrawable.getInstance(bitmap,
res.getDimension(R.dimen.car_fullscreen_user_pod_image_avatar_height));
- ((ImageView) view.findViewById(R.id.user_loading_avatar))
+ ((ImageView) mView.findViewById(R.id.user_loading_avatar))
.setImageDrawable(drawable);
}
- TextView msgView = view.findViewById(R.id.user_loading);
+ TextView msgView = mView.findViewById(R.id.user_loading);
// TODO(b/145132885): use constant from CarSettings
boolean showInfo = "true".equals(Settings.Global.getString(
@@ -92,7 +101,17 @@
} else {
msgView.setText(res.getString(R.string.car_loading_profile));
}
- setView(view);
+ setView(mView);
+ }
+
+ @Override
+ public void show() {
+ super.show();
+ hideNavigationBar();
+ }
+
+ private void hideNavigationBar() {
+ mView.getWindowInsetsController().hide(WindowInsets.Type.navigationBars());
}
/**
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
index bbe4ed1..7e63e72 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingService.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -181,6 +181,7 @@
// (app uninstall/disable will be notified by RoleManager.)
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageFilter.addDataScheme("package");
mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL,
@@ -255,6 +256,9 @@
handlePackageAddedReplacing(packageName, userId);
}
break;
+ case Intent.ACTION_PACKAGE_CHANGED:
+ handlePackageAddedReplacing(packageName, userId);
+ break;
}
}
};
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index b546120..c2c79d3 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -324,7 +324,7 @@
}
/*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
- //Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
+ //Log.i(TAG, "setBluetoothScoOn: " + on + " " + eventSource);
synchronized (mDeviceStateLock) {
if (on) {
// do not accept SCO ON if SCO audio is not connected
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 36332c0..93d1bed 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -58,6 +58,7 @@
}
// List of clients having issued a SCO start request
+ @GuardedBy("BtHelper.this")
private final @NonNull ArrayList<ScoClient> mScoClients = new ArrayList<ScoClient>();
// BluetoothHeadset API to control SCO connection
@@ -356,9 +357,8 @@
// client is created.
final long ident = Binder.clearCallingIdentity();
try {
- eventSource += " client count before=" + client.getCount();
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
- client.incCount(scoAudioMode);
+ client.requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
} catch (NullPointerException e) {
Log.e(TAG, "Null ScoClient", e);
}
@@ -375,9 +375,15 @@
// and this must be done on behalf of system server to make sure permissions are granted.
final long ident = Binder.clearCallingIdentity();
if (client != null) {
- eventSource += " client count before=" + client.getCount();
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
- client.decCount();
+ client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
+ SCO_MODE_VIRTUAL_CALL);
+ // If a disconnection is pending, the client will be removed whne clearAllScoClients()
+ // is called form receiveBtEvent()
+ if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
+ && mScoAudioState != SCO_STATE_DEACTIVATING) {
+ client.remove(false /*stop */, true /*unregister*/);
+ }
}
Binder.restoreCallingIdentity(ident);
}
@@ -657,25 +663,33 @@
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void scoClientDied(Object obj) {
final ScoClient client = (ScoClient) obj;
+ client.remove(true /*stop*/, false /*unregister*/);
Log.w(TAG, "SCO client died");
- int index = mScoClients.indexOf(client);
- if (index < 0) {
- Log.w(TAG, "unregistered SCO client died");
- } else {
- client.clearCount(true);
- mScoClients.remove(client);
- }
}
private class ScoClient implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death
private int mCreatorPid;
- private int mStartcount; // number of SCO connections started by this client
ScoClient(IBinder cb) {
mCb = cb;
mCreatorPid = Binder.getCallingPid();
- mStartcount = 0;
+ }
+
+ public void registerDeathRecipient() {
+ try {
+ mCb.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "ScoClient could not link to " + mCb + " binder death");
+ }
+ }
+
+ public void unregisterDeathRecipient() {
+ try {
+ mCb.unlinkToDeath(this, 0);
+ } catch (NoSuchElementException e) {
+ Log.w(TAG, "ScoClient could not not unregistered to binder");
+ }
}
@Override
@@ -685,70 +699,6 @@
mDeviceBroker.postScoClientDied(this);
}
- // @GuardedBy("AudioDeviceBroker.mSetModeLock")
- // @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- @GuardedBy("BtHelper.this")
- void incCount(int scoAudioMode) {
- if (!requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode)) {
- Log.e(TAG, "Request sco connected with scoAudioMode("
- + scoAudioMode + ") failed");
- return;
- }
- if (mStartcount == 0) {
- try {
- mCb.linkToDeath(this, 0);
- } catch (RemoteException e) {
- // client has already died!
- Log.w(TAG, "ScoClient incCount() could not link to "
- + mCb + " binder death");
- }
- }
- mStartcount++;
- }
-
- // @GuardedBy("AudioDeviceBroker.mSetModeLock")
- // @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- @GuardedBy("BtHelper.this")
- void decCount() {
- if (mStartcount == 0) {
- Log.w(TAG, "ScoClient.decCount() already 0");
- } else {
- mStartcount--;
- if (mStartcount == 0) {
- try {
- mCb.unlinkToDeath(this, 0);
- } catch (NoSuchElementException e) {
- Log.w(TAG, "decCount() going to 0 but not registered to binder");
- }
- }
- if (!requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0)) {
- Log.w(TAG, "Request sco disconnected with scoAudioMode(0) failed");
- }
- }
- }
-
- // @GuardedBy("AudioDeviceBroker.mSetModeLock")
- // @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- @GuardedBy("BtHelper.this")
- void clearCount(boolean stopSco) {
- if (mStartcount != 0) {
- try {
- mCb.unlinkToDeath(this, 0);
- } catch (NoSuchElementException e) {
- Log.w(TAG, "clearCount() mStartcount: "
- + mStartcount + " != 0 but not registered to binder");
- }
- }
- mStartcount = 0;
- if (stopSco) {
- requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
- }
- }
-
- int getCount() {
- return mStartcount;
- }
-
IBinder getBinder() {
return mCb;
}
@@ -757,23 +707,14 @@
return mCreatorPid;
}
- private int totalCount() {
- int count = 0;
- for (ScoClient mScoClient : mScoClients) {
- count += mScoClient.getCount();
- }
- return count;
- }
-
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
//@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
private boolean requestScoState(int state, int scoAudioMode) {
checkScoAudioState();
- int clientCount = totalCount();
- if (clientCount != 0) {
+ if (mScoClients.size() != 1) {
Log.i(TAG, "requestScoState: state=" + state + ", scoAudioMode=" + scoAudioMode
- + ", clientCount=" + clientCount);
+ + ", num SCO clients=" + mScoClients.size());
return true;
}
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
@@ -842,12 +783,14 @@
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
break;
+ case SCO_STATE_ACTIVE_INTERNAL:
+ Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
+ break;
default:
Log.w(TAG, "requestScoState: failed to connect in state "
+ mScoAudioState + ", scoAudioMode=" + scoAudioMode);
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
return false;
-
}
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
switch (mScoAudioState) {
@@ -893,6 +836,18 @@
}
return true;
}
+
+ @GuardedBy("BtHelper.this")
+ void remove(boolean stop, boolean unregister) {
+ if (unregister) {
+ unregisterDeathRecipient();
+ }
+ if (stop) {
+ requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
+ SCO_MODE_VIRTUAL_CALL);
+ }
+ mScoClients.remove(this);
+ }
}
//-----------------------------------------------------
@@ -946,6 +901,7 @@
}
+ @GuardedBy("BtHelper.this")
private ScoClient getScoClient(IBinder cb, boolean create) {
for (ScoClient existingClient : mScoClients) {
if (existingClient.getBinder() == cb) {
@@ -954,6 +910,7 @@
}
if (create) {
ScoClient newClient = new ScoClient(cb);
+ newClient.registerDeathRecipient();
mScoClients.add(newClient);
return newClient;
}
@@ -964,18 +921,16 @@
//@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
private void clearAllScoClients(int exceptPid, boolean stopSco) {
- ScoClient savedClient = null;
+ final ArrayList<ScoClient> clients = new ArrayList<ScoClient>();
for (ScoClient cl : mScoClients) {
if (cl.getPid() != exceptPid) {
- cl.clearCount(stopSco);
- } else {
- savedClient = cl;
+ clients.add(cl);
}
}
- mScoClients.clear();
- if (savedClient != null) {
- mScoClients.add(savedClient);
+ for (ScoClient cl : clients) {
+ cl.remove(stopSco, true /*unregister*/);
}
+
}
private boolean getBluetoothHeadset() {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index eb0257e..bcf262d 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -51,6 +51,7 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -75,6 +76,7 @@
private final PowerManager mPowerManager;
private final PowerManagerInternal mPowerManagerInternal;
private final PowerManager.WakeLock mDozeWakeLock;
+ private final ActivityTaskManagerInternal mAtmInternal;
private Binder mCurrentDreamToken;
private ComponentName mCurrentDreamName;
@@ -97,6 +99,7 @@
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
+ mAtmInternal = getLocalService(ActivityTaskManagerInternal.class);
mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
mDozeConfig = new AmbientDisplayConfiguration(mContext);
}
@@ -383,8 +386,10 @@
PowerManager.WakeLock wakeLock = mPowerManager
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
- mHandler.post(wakeLock.wrap(
- () -> mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock)));
+ mHandler.post(wakeLock.wrap(() -> {
+ mAtmInternal.notifyDreamStateChanged(true);
+ mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock);
+ }));
}
private void stopDreamLocked(final boolean immediate) {
@@ -422,6 +427,7 @@
}
mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ mAtmInternal.notifyDreamStateChanged(false);
}
private void checkPermission(String permission) {
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 44ab438..273fd48 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -91,6 +91,7 @@
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import java.util.function.Supplier;
/** Implementation of {@link AppIntegrityManagerService}. */
public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
@@ -125,6 +126,7 @@
private final Context mContext;
private final Handler mHandler;
private final PackageManagerInternal mPackageManagerInternal;
+ private final Supplier<PackageParser2> mParserSupplier;
private final RuleEvaluationEngine mEvaluationEngine;
private final IntegrityFileManager mIntegrityFileManager;
@@ -136,6 +138,7 @@
return new AppIntegrityManagerServiceImpl(
context,
LocalServices.getService(PackageManagerInternal.class),
+ PackageParser2::forParsingFileWithDefaults,
RuleEvaluationEngine.getRuleEvaluationEngine(),
IntegrityFileManager.getInstance(),
handlerThread.getThreadHandler());
@@ -145,11 +148,13 @@
AppIntegrityManagerServiceImpl(
Context context,
PackageManagerInternal packageManagerInternal,
+ Supplier<PackageParser2> parserSupplier,
RuleEvaluationEngine evaluationEngine,
IntegrityFileManager integrityFileManager,
Handler handler) {
mContext = context;
mPackageManagerInternal = packageManagerInternal;
+ mParserSupplier = parserSupplier;
mEvaluationEngine = evaluationEngine;
mIntegrityFileManager = integrityFileManager;
mHandler = handler;
@@ -562,8 +567,7 @@
throw new IllegalArgumentException("Installation path is null, package not found");
}
- PackageParser2 parser = new PackageParser2(null, false, null, null, null);
- try {
+ try (PackageParser2 parser = mParserSupplier.get()) {
ParsedPackage pkg = parser.parsePackage(installationPath, 0, false);
int flags = PackageManager.GET_SIGNING_CERTIFICATES | PackageManager.GET_META_DATA;
pkg.setSigningDetails(ParsingPackageUtils.collectCertificates(pkg, false));
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 0bba172..b28350d 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -493,7 +493,7 @@
}
}
- //TODO: Review this is handling multi-user properly.
+ //TODO(b/136703681): Review this is handling multi-user properly.
void switchUser() {
synchronized (mLock) {
int userId = ActivityManager.getCurrentUser();
@@ -568,7 +568,9 @@
UserRecord userRecord = routerRecord.mUserRecord;
userRecord.mRouterRecords.remove(routerRecord);
- //TODO: update discovery request
+ userRecord.mHandler.sendMessage(
+ obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
+ userRecord.mHandler));
routerRecord.dispose();
disposeUserIfNeededLocked(userRecord); // since router removed from user
}
@@ -793,7 +795,7 @@
}
long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
- //TODO: Use MediaRouter2's OnCreateSessionListener to send proper session hints.
+ //TODO(b/152851868): Use MediaRouter2's OnCreateSessionListener to send session hints.
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::requestCreateSessionOnHandler,
routerRecord.mUserRecord.mHandler,
@@ -1146,7 +1148,6 @@
return mSessionToRouterMap.get(uniqueSessionId);
}
- //TODO: notify session info updates
private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) {
int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId());
MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
@@ -1323,7 +1324,7 @@
return true;
}
- //TODO: Handle RCN case.
+ //TODO(b/152950479): Handle RCN case.
if (routerRecord == null) {
Slog.w(TAG, "Ignoring " + description + " route from unknown router.");
return false;
@@ -1403,7 +1404,8 @@
private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
- notifySessionCreatedToManagers(getManagers(), sessionInfo);
+ notifySessionCreatedToManagers(getManagers(),
+ toOriginalRequestId(uniqueRequestId), sessionInfo);
if (uniqueRequestId == REQUEST_ID_NONE) {
// The session is created without any matching request.
@@ -1457,7 +1459,7 @@
private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo) {
List<IMediaRouter2Manager> managers = getManagers();
- notifySessionInfosChangedToManagers(managers);
+ notifySessionInfoChangedToManagers(managers, sessionInfo);
// For system provider, notify all routers.
if (provider == mSystemProvider) {
@@ -1480,7 +1482,7 @@
private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
@NonNull RoutingSessionInfo sessionInfo) {
List<IMediaRouter2Manager> managers = getManagers();
- notifySessionInfosChangedToManagers(managers);
+ notifySessionInfoChangedToManagers(managers, sessionInfo);
RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
if (routerRecord == null) {
@@ -1558,7 +1560,8 @@
private void notifySessionCreationFailedToRouter(@NonNull RouterRecord routerRecord,
int requestId) {
try {
- routerRecord.mRouter.notifySessionCreated(requestId, /* sessionInfo= */ null);
+ routerRecord.mRouter.notifySessionCreated(requestId,
+ /* sessionInfo= */ null);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to notify router of the session creation failure."
+ " Router probably died.", ex);
@@ -1731,10 +1734,10 @@
}
private void notifySessionCreatedToManagers(@NonNull List<IMediaRouter2Manager> managers,
- @NonNull RoutingSessionInfo sessionInfo) {
+ int requestId, @NonNull RoutingSessionInfo sessionInfo) {
for (IMediaRouter2Manager manager : managers) {
try {
- manager.notifySessionCreated(sessionInfo);
+ manager.notifySessionCreated(requestId, sessionInfo);
} catch (RemoteException ex) {
Slog.w(TAG, "notifySessionCreatedToManagers: "
+ "failed to notify. Manager probably died.", ex);
@@ -1742,11 +1745,12 @@
}
}
- private void notifySessionInfosChangedToManagers(
- @NonNull List<IMediaRouter2Manager> managers) {
+ private void notifySessionInfoChangedToManagers(
+ @NonNull List<IMediaRouter2Manager> managers,
+ @NonNull RoutingSessionInfo sessionInfo) {
for (IMediaRouter2Manager manager : managers) {
try {
- manager.notifySessionsUpdated();
+ manager.notifySessionUpdated(sessionInfo);
} catch (RemoteException ex) {
Slog.w(TAG, "notifySessionInfosChangedToManagers: "
+ "failed to notify. Manager probably died.", ex);
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 32cfaf6..dbb246e 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -20,6 +20,7 @@
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
@@ -1798,6 +1799,7 @@
.setAtomId(PACKAGE_NOTIFICATION_PREFERENCES);
final PackagePreferences r = mPackagePreferences.valueAt(i);
event.writeInt(r.uid);
+ event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
event.writeInt(r.importance);
event.writeInt(r.visibility);
event.writeInt(r.lockedAppFields);
@@ -1825,6 +1827,7 @@
StatsEvent.Builder event = StatsEvent.newBuilder()
.setAtomId(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES);
event.writeInt(r.uid);
+ event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
event.writeString(channel.getId());
event.writeString(channel.getName().toString());
event.writeString(channel.getDescription());
@@ -1856,6 +1859,7 @@
StatsEvent.Builder event = StatsEvent.newBuilder()
.setAtomId(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES);
event.writeInt(r.uid);
+ event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
event.writeString(groupChannel.getId());
event.writeString(groupChannel.getName().toString());
event.writeString(groupChannel.getDescription());
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 805d918..09b782d 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -674,7 +674,8 @@
Trace.endSection();
if (callingPkgSetting != null) {
- if (!mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) {
+ if (callingPkgSetting.pkg != null
+ && !mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "DISABLED");
}
@@ -682,7 +683,8 @@
}
} else {
for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
- if (!mFeatureConfig.packageIsEnabled(callingSharedPkgSettings.valueAt(i).pkg)) {
+ final AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).pkg;
+ if (pkg != null && !mFeatureConfig.packageIsEnabled(pkg)) {
if (DEBUG_LOGGING) {
log(callingSetting, targetPkgSetting, "DISABLED");
}
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index f497f11..f1e1433 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -54,6 +54,7 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.server.IntentResolver;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -207,33 +208,57 @@
}
/** Returns the given activity */
- ParsedActivity getActivity(ComponentName component) {
+ @Nullable
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public ParsedActivity getActivity(@NonNull ComponentName component) {
synchronized (mLock) {
return mActivities.mActivities.get(component);
}
}
/** Returns the given provider */
- ParsedProvider getProvider(ComponentName component) {
+ @Nullable
+ ParsedProvider getProvider(@NonNull ComponentName component) {
synchronized (mLock) {
return mProviders.mProviders.get(component);
}
}
/** Returns the given receiver */
- ParsedActivity getReceiver(ComponentName component) {
+ @Nullable
+ ParsedActivity getReceiver(@NonNull ComponentName component) {
synchronized (mLock) {
return mReceivers.mActivities.get(component);
}
}
/** Returns the given service */
- ParsedService getService(ComponentName component) {
+ @Nullable
+ ParsedService getService(@NonNull ComponentName component) {
synchronized (mLock) {
return mServices.mServices.get(component);
}
}
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public boolean componentExists(@NonNull ComponentName componentName) {
+ synchronized (mLock) {
+ ParsedMainComponent component = mActivities.mActivities.get(componentName);
+ if (component != null) {
+ return true;
+ }
+ component = mReceivers.mActivities.get(componentName);
+ if (component != null) {
+ return true;
+ }
+ component = mServices.mServices.get(componentName);
+ if (component != null) {
+ return true;
+ }
+ return mProviders.mProviders.get(componentName) != null;
+ }
+ }
+
@Nullable
List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags,
@PrivateResolveFlags int privateResolveFlags, int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 414449d..f96ab1d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -674,7 +674,7 @@
final ServiceThread mHandlerThread;
- final PackageHandler mHandler;
+ final Handler mHandler;
private final ProcessLoggingHandler mProcessLoggingHandler;
@@ -1033,15 +1033,65 @@
}
}
- private final AppsFilter mAppsFilter;
-
- class PackageParserCallback extends PackageParser2.Callback {
- @Override public final boolean hasFeature(String feature) {
- return PackageManagerService.this.hasSystemFeature(feature, 0);
- }
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class TestParams {
+ public ApexManager apexManager;
+ public @Nullable String appPredictionServicePackage;
+ public ArtManagerService artManagerService;
+ public @Nullable String configuratorPackage;
+ public int defParseFlags;
+ public DexManager dexManager;
+ public List<ScanPartition> dirsToScanAsSystem;
+ public @Nullable String documenterPackage;
+ public boolean factoryTest;
+ public ArrayMap<String, FeatureInfo> availableFeatures;
+ public Handler handler;
+ public ServiceThread handlerThread;
+ public @Nullable String incidentReportApproverPackage;
+ public IncrementalManager incrementalManager;
+ public PackageInstallerService installerService;
+ public InstantAppRegistry instantAppRegistry;
+ public InstantAppResolverConnection instantAppResolverConnection;
+ public ComponentName instantAppResolverSettingsComponent;
+ public @Nullable IntentFilterVerifier<ParsedIntentInfo> intentFilterVerifier;
+ public @Nullable ComponentName intentFilterVerifierComponent;
+ public boolean isPreNmr1Upgrade;
+ public boolean isPreNupgrade;
+ public boolean isPreQupgrade;
+ public boolean isUpgrade;
+ public DisplayMetrics Metrics;
+ public ModuleInfoProvider moduleInfoProvider;
+ public MoveCallbacks moveCallbacks;
+ public boolean onlyCore;
+ public OverlayConfig overlayConfig;
+ public PackageDexOptimizer packageDexOptimizer;
+ public PackageParser2.Callback packageParserCallback;
+ public IPermissionManager permissionManagerService;
+ public PendingPackageBroadcasts pendingPackageBroadcasts;
+ public PackageManagerInternal pmInternal;
+ public ProcessLoggingHandler processLoggingHandler;
+ public ProtectedPackages protectedPackages;
+ public @NonNull String requiredInstallerPackage;
+ public @NonNull String requiredPermissionControllerPackage;
+ public @NonNull String requiredUninstallerPackage;
+ public @Nullable String requiredVerifierPackage;
+ public String[] separateProcesses;
+ public @NonNull String servicesExtensionPackageName;
+ public @Nullable String setupWizardPackage;
+ public @NonNull String sharedSystemSharedLibraryPackageName;
+ public @Nullable String storageManagerPackage;
+ public @Nullable String defaultTextClassifierPackage;
+ public @Nullable String systemTextClassifierPackage;
+ public ViewCompiler viewCompiler;
+ public @Nullable String wellbeingPackage;
+ public @Nullable String retailDemoPackage;
+ public ComponentName resolveComponentName;
+ public ArrayMap<String, AndroidPackage> packages;
}
- final PackageParser2.Callback mPackageParserCallback = new PackageParserCallback();
+ private final AppsFilter mAppsFilter;
+
+ final PackageParser2.Callback mPackageParserCallback;
// Currently known shared libraries.
final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
@@ -1402,7 +1452,8 @@
}
// Set of pending broadcasts for aggregating enable/disable of components.
- static class PendingPackageBroadcasts {
+ @VisibleForTesting(visibility = Visibility.PACKAGE)
+ public static class PendingPackageBroadcasts {
// for each user id, a map of <package name -> components within that package>
final SparseArray<ArrayMap<String, ArrayList<String>>> mUidMap;
@@ -1465,7 +1516,7 @@
return map;
}
}
- final PendingPackageBroadcasts mPendingBroadcasts = new PendingPackageBroadcasts();
+ final PendingPackageBroadcasts mPendingBroadcasts;
static final int SEND_PENDING_BROADCAST = 1;
static final int INIT_COPY = 5;
@@ -2682,6 +2733,82 @@
}
}
+ /**
+ * A extremely minimal constructor designed to start up a PackageManagerService instance for
+ * testing.
+ *
+ * It is assumed that all methods under test will mock the internal fields and thus
+ * none of the initialization is needed.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public PackageManagerService(@NonNull Injector injector, @NonNull TestParams testParams) {
+ mInjector = injector;
+ mInjector.bootstrap(this);
+ mAppsFilter = injector.getAppsFilter();
+ mComponentResolver = injector.getComponentResolver();
+ mContext = injector.getContext();
+ mInstaller = injector.getInstaller();
+ mInstallLock = injector.getInstallLock();
+ mLock = injector.getLock();
+ mPermissionManager = injector.getPermissionManagerServiceInternal();
+ mSettings = injector.getSettings();
+ mUserManager = injector.getUserManagerService();
+
+ mApexManager = testParams.apexManager;
+ mArtManagerService = testParams.artManagerService;
+ mAvailableFeatures = testParams.availableFeatures;
+ mDefParseFlags = testParams.defParseFlags;
+ mDexManager = testParams.dexManager;
+ mDirsToScanAsSystem = testParams.dirsToScanAsSystem;
+ mFactoryTest = testParams.factoryTest;
+ mHandler = testParams.handler;
+ mHandlerThread = testParams.handlerThread;
+ mIncrementalManager = testParams.incrementalManager;
+ mInstallerService = testParams.installerService;
+ mInstantAppRegistry = testParams.instantAppRegistry;
+ mInstantAppResolverConnection = testParams.instantAppResolverConnection;
+ mInstantAppResolverSettingsComponent = testParams.instantAppResolverSettingsComponent;
+ mIntentFilterVerifier = testParams.intentFilterVerifier;
+ mIntentFilterVerifierComponent = testParams.intentFilterVerifierComponent;
+ mIsPreNMR1Upgrade = testParams.isPreNmr1Upgrade;
+ mIsPreNUpgrade = testParams.isPreNupgrade;
+ mIsPreQUpgrade = testParams.isPreQupgrade;
+ mIsUpgrade = testParams.isUpgrade;
+ mMetrics = testParams.Metrics;
+ mModuleInfoProvider = testParams.moduleInfoProvider;
+ mMoveCallbacks = testParams.moveCallbacks;
+ mOnlyCore = testParams.onlyCore;
+ mOverlayConfig = testParams.overlayConfig;
+ mPackageDexOptimizer = testParams.packageDexOptimizer;
+ mPackageParserCallback = testParams.packageParserCallback;
+ mPendingBroadcasts = testParams.pendingPackageBroadcasts;
+ mPermissionManagerService = testParams.permissionManagerService;
+ mPmInternal = testParams.pmInternal;
+ mProcessLoggingHandler = testParams.processLoggingHandler;
+ mProtectedPackages = testParams.protectedPackages;
+ mSeparateProcesses = testParams.separateProcesses;
+ mViewCompiler = testParams.viewCompiler;
+ mRequiredVerifierPackage = testParams.requiredVerifierPackage;
+ mRequiredInstallerPackage = testParams.requiredInstallerPackage;
+ mRequiredUninstallerPackage = testParams.requiredUninstallerPackage;
+ mRequiredPermissionControllerPackage = testParams.requiredPermissionControllerPackage;
+ mSetupWizardPackage = testParams.setupWizardPackage;
+ mStorageManagerPackage = testParams.storageManagerPackage;
+ mDefaultTextClassifierPackage = testParams.defaultTextClassifierPackage;
+ mSystemTextClassifierPackageName = testParams.systemTextClassifierPackage;
+ mWellbeingPackage = testParams.wellbeingPackage;
+ mRetailDemoPackage = testParams.retailDemoPackage;
+ mDocumenterPackage = testParams.documenterPackage;
+ mConfiguratorPackage = testParams.configuratorPackage;
+ mAppPredictionServicePackage = testParams.appPredictionServicePackage;
+ mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
+ mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
+ mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
+
+ mResolveComponentName = testParams.resolveComponentName;
+ mPackages.putAll(testParams.packages);
+ }
+
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
PackageManager.invalidatePackageInfoCache();
PackageManager.disableApplicationInfoCache();
@@ -2689,6 +2816,8 @@
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
Trace.TRACE_TAG_PACKAGE_MANAGER);
+ mPendingBroadcasts = new PendingPackageBroadcasts();
+
mInjector = injector;
mInjector.bootstrap(this);
mLock = injector.getLock();
@@ -2720,6 +2849,18 @@
mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
mIncrementalManager =
(IncrementalManager) mContext.getSystemService(Context.INCREMENTAL_SERVICE);
+ PlatformCompat platformCompat = mInjector.getCompatibility();
+ mPackageParserCallback = new PackageParser2.Callback() {
+ @Override
+ public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
+ return platformCompat.isChangeEnabled(changeId, appInfo);
+ }
+
+ @Override
+ public boolean hasFeature(String feature) {
+ return PackageManagerService.this.hasSystemFeature(feature, 0);
+ }
+ };
// CHECKSTYLE:ON IndentationCheck
t.traceEnd();
@@ -3075,6 +3216,8 @@
}
+ packageParser.close();
+
List<Runnable> unfinishedTasks = executorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
@@ -5160,7 +5303,7 @@
AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());
if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
- PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+ PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
if (ps == null) return null;
if (shouldFilterApplicationLocked(
ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
@@ -8901,12 +9044,11 @@
private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
- PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null,
- mPackageParserCallback);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final ParsedPackage parsedPackage;
- try {
+ try (PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null,
+ mPackageParserCallback)) {
parsedPackage = pp.parsePackage(scanFile, parseFlags, false);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
@@ -15602,6 +15744,12 @@
// these install state changes will be persisted in the
// upcoming call to mSettings.writeLPr().
}
+
+ if (allUsers != null) {
+ for (int currentUserId : allUsers) {
+ ps.resetOverrideComponentLabelIcon(currentUserId);
+ }
+ }
}
// Retrieve the overlays for shared libraries of the package.
@@ -16676,12 +16824,10 @@
| PackageParser.PARSE_ENFORCE_CODE
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
- PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
- mPackageParserCallback);
-
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
ParsedPackage parsedPackage;
- try {
+ try (PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
+ mPackageParserCallback)) {
parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
} catch (PackageParserException e) {
@@ -16746,8 +16892,6 @@
"Instant app package must be signed with APK Signature Scheme v2 or greater");
}
- // Get rid of all references to package scan path via parser.
- pp = null;
boolean systemApp = false;
boolean replace = false;
synchronized (mLock) {
@@ -20174,6 +20318,86 @@
}
@Override
+ public void overrideLabelAndIcon(@NonNull ComponentName componentName,
+ @NonNull String nonLocalizedLabel, int icon, int userId) {
+ if (TextUtils.isEmpty(nonLocalizedLabel)) {
+ throw new IllegalArgumentException("Override label should be a valid String");
+ }
+ updateComponentLabelIcon(componentName, nonLocalizedLabel, icon, userId);
+ }
+
+ @Override
+ public void restoreLabelAndIcon(@NonNull ComponentName componentName, int userId) {
+ updateComponentLabelIcon(componentName, null, null, userId);
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public void updateComponentLabelIcon(/*@NonNull*/ ComponentName componentName,
+ @Nullable String nonLocalizedLabel, @Nullable Integer icon, int userId) {
+ if (componentName == null) {
+ throw new IllegalArgumentException("Must specify a component");
+ }
+
+ boolean componentExists = mComponentResolver.componentExists(componentName);
+ if (!componentExists) {
+ throw new IllegalArgumentException("Component " + componentName + " not found");
+ }
+
+ int callingUid = Binder.getCallingUid();
+
+ String componentPkgName = componentName.getPackageName();
+ int componentUid = getPackageUid(componentPkgName, 0, userId);
+ if (!UserHandle.isSameApp(callingUid, componentUid)) {
+ throw new SecurityException("The calling UID (" + callingUid + ")"
+ + " does not match the target UID");
+ }
+
+ String allowedCallerPkg = mContext.getString(R.string.config_overrideComponentUiPackage);
+ if (TextUtils.isEmpty(allowedCallerPkg)) {
+ throw new SecurityException(
+ "There is no package defined as allowed to change a component's label or icon");
+ }
+
+ int allowedCallerUid = getPackageUid(allowedCallerPkg, PackageManager.MATCH_SYSTEM_ONLY,
+ userId);
+ if (allowedCallerUid == -1 || !UserHandle.isSameApp(callingUid, allowedCallerUid)) {
+ throw new SecurityException("The calling UID (" + callingUid + ")"
+ + " is not allowed to change a component's label or icon");
+ }
+
+ synchronized (mLock) {
+ AndroidPackage pkg = mPackages.get(componentPkgName);
+ PackageSetting pkgSetting = getPackageSetting(componentPkgName);
+ if (pkg == null || pkgSetting == null
+ || (!pkg.isSystem() && !pkgSetting.getPkgState().isUpdatedSystemApp())) {
+ throw new SecurityException(
+ "Changing the label is not allowed for " + componentName);
+ }
+
+ if (!pkgSetting.overrideNonLocalizedLabelAndIcon(componentName, nonLocalizedLabel,
+ icon, userId)) {
+ // Nothing changed
+ return;
+ }
+ }
+
+ ArrayList<String> components = mPendingBroadcasts.get(userId, componentPkgName);
+ if (components == null) {
+ components = new ArrayList<>();
+ mPendingBroadcasts.put(userId, componentPkgName, components);
+ }
+
+ String className = componentName.getClassName();
+ if (!components.contains(className)) {
+ components.add(className);
+ }
+
+ if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
+ mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
+ }
+ }
+
+ @Override
public void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags, int userId) {
if (!mUserManager.exists(userId)) return;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 9a8692d..432d7f3 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -26,6 +26,7 @@
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionsState;
import com.android.server.pm.pkg.PackageStateUnserialized;
@@ -43,6 +44,7 @@
public class PackageSetting extends PackageSettingBase {
int appId;
+ @Nullable
public AndroidPackage pkg;
/**
* WARNING. The object reference is important. We perform integer equality and NOT
@@ -68,7 +70,8 @@
@NonNull
private PackageStateUnserialized pkgState = new PackageStateUnserialized();
- PackageSetting(String name, String realName, File codePath, File resourcePath,
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public PackageSetting(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
long pVersionCode, int pkgFlags, int privateFlags,
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 7cb3df5..00a5fe76 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -21,6 +21,9 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
@@ -697,6 +700,26 @@
return userState.harmfulAppWarning;
}
+ /**
+ * @see PackageUserState#overrideLabelAndIcon(ComponentName, String, Integer)
+ *
+ * @param userId the specific user to change the label/icon for
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public boolean overrideNonLocalizedLabelAndIcon(@NonNull ComponentName component,
+ @Nullable String label, @Nullable Integer icon, @UserIdInt int userId) {
+ return modifyUserState(userId).overrideLabelAndIcon(component, label, icon);
+ }
+
+ /**
+ * @see PackageUserState#resetOverrideComponentLabelIcon()
+ *
+ * @param userId the specific user to reset
+ */
+ public void resetOverrideComponentLabelIcon(@UserIdInt int userId) {
+ modifyUserState(userId).resetOverrideComponentLabelIcon();
+ }
+
protected PackageSettingBase updateFrom(PackageSettingBase other) {
super.copyFrom(other);
this.codePath = other.codePath;
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index ec9746d..3e2ab05 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -18,9 +18,11 @@
import android.content.pm.ApplicationInfo;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.permission.PermissionsState;
-abstract class SettingBase {
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public abstract class SettingBase {
int pkgFlags;
int pkgPrivateFlags;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f6ca87d..091535d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -91,6 +91,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -418,6 +419,21 @@
/** Settings and other information about permissions */
final PermissionSettings mPermissions;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public Settings(Map<String, PackageSetting> pkgSettings) {
+ mLock = new Object();
+ mPackages.putAll(pkgSettings);
+ mSystemDir = null;
+ mPermissions = null;
+ mRuntimePermissionsPersistence = null;
+ mSettingsFilename = null;
+ mBackupSettingsFilename = null;
+ mPackageListFilename = null;
+ mStoppedPackagesFilename = null;
+ mBackupStoppedPackagesFilename = null;
+ mKernelMappingFilename = null;
+ }
+
Settings(File dataDir, PermissionSettings permission,
Object lock) {
mLock = lock;
@@ -4328,8 +4344,9 @@
return userState.isMatch(componentInfo, flags);
}
- boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedMainComponent component, int flags,
- int userId) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedMainComponent component,
+ int flags, int userId) {
final PackageSetting ps = mPackages.get(component.getPackageName());
if (ps == null) return false;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 8768ab0..8d53d15 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2385,6 +2385,30 @@
}
}
+ public boolean isSharingShortcut(int callingUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId,
+ @NonNull IntentFilter filter) {
+ verifyCaller(callingPackage, callingUserId);
+ enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS,
+ "isSharingShortcut");
+
+ synchronized (mLock) {
+ throwIfUserLockedL(userId);
+ throwIfUserLockedL(callingUserId);
+
+ final List<ShortcutManager.ShareShortcutInfo> matchedTargets =
+ getPackageShortcutsLocked(packageName, userId)
+ .getMatchingShareTargets(filter);
+ final int matchedSize = matchedTargets.size();
+ for (int i = 0; i < matchedSize; i++) {
+ if (matchedTargets.get(i).getShortcutInfo().getId().equals(shortcutId)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
@GuardedBy("mLock")
private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
@UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
@@ -2969,6 +2993,18 @@
callingPackage, intentFilter, userId).getList();
}
+ @Override
+ public boolean isSharingShortcut(int callingUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId,
+ @NonNull IntentFilter filter) {
+ Preconditions.checkStringNotEmpty(callingPackage, "callingPackage");
+ Preconditions.checkStringNotEmpty(packageName, "packageName");
+ Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
+
+ return ShortcutService.this.isSharingShortcut(callingUserId, callingPackage,
+ packageName, shortcutId, userId, filter);
+ }
+
private void updateCachedShortcutsInternal(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
@NonNull List<String> shortcutIds, int userId, boolean doCache) {
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 5a1e8e2..137e0aa 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -48,6 +48,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import com.android.internal.util.ArrayUtils;
@@ -271,7 +272,7 @@
ActivityInfo info =
PackageInfoWithoutStateUtils.generateActivityInfoUnchecked(a, applicationInfo);
- assignSharedFieldsForComponentInfo(info, a, pkgSetting);
+ assignSharedFieldsForComponentInfo(info, a, pkgSetting, userId);
return info;
}
@@ -306,7 +307,7 @@
ServiceInfo info =
PackageInfoWithoutStateUtils.generateServiceInfoUnchecked(s, applicationInfo);
- assignSharedFieldsForComponentInfo(info, s, pkgSetting);
+ assignSharedFieldsForComponentInfo(info, s, pkgSetting, userId);
return info;
}
@@ -333,7 +334,7 @@
}
ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfoUnchecked(p, flags,
applicationInfo);
- assignSharedFieldsForComponentInfo(info, p, pkgSetting);
+ assignSharedFieldsForComponentInfo(info, p, pkgSetting, userId);
return info;
}
@@ -358,7 +359,7 @@
info.nativeLibraryDir = pkg.getNativeLibraryDir();
info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
- assignStateFieldsForPackageItemInfo(info, i, pkgSetting);
+ assignStateFieldsForPackageItemInfo(info, i, pkgSetting, userId);
return info;
}
@@ -426,8 +427,9 @@
}
private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
- @NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting) {
- assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting);
+ @NonNull ParsedMainComponent mainComponent, @Nullable PackageSetting pkgSetting,
+ int userId) {
+ assignStateFieldsForPackageItemInfo(componentInfo, mainComponent, pkgSetting, userId);
componentInfo.descriptionRes = mainComponent.getDescriptionRes();
componentInfo.directBootAware = mainComponent.isDirectBootAware();
componentInfo.enabled = mainComponent.isEnabled();
@@ -436,8 +438,12 @@
private static void assignStateFieldsForPackageItemInfo(
@NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component,
- @Nullable PackageSetting pkgSetting) {
- // TODO(b/135203078): Add setting related state
+ @Nullable PackageSetting pkgSetting, int userId) {
+ Pair<CharSequence, Integer> labelAndIcon =
+ ParsedComponentStateUtils.getNonLocalizedLabelAndIcon(component, pkgSetting,
+ userId);
+ packageItemInfo.nonLocalizedLabel = labelAndIcon.first;
+ packageItemInfo.icon = labelAndIcon.second;
}
@CheckResult
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index d561b9c..e860c48 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -17,7 +17,10 @@
package com.android.server.pm.parsing;
import android.annotation.AnyThread;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.ParsingPackage;
@@ -27,10 +30,13 @@
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.TypedArray;
import android.os.Build;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Slog;
+import com.android.server.compat.PlatformCompat;
+import com.android.server.pm.PackageManagerService;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -39,19 +45,53 @@
/**
* The v2 of {@link PackageParser} for use when parsing is initiated in the server and must
* contain state contained by the server.
+ *
+ * The {@link AutoCloseable} helps signal that this class contains resources that must be freed.
+ * Although it is sufficient to release references to an instance of this class and let it get
+ * collected automatically.
*/
-public class PackageParser2 {
+public class PackageParser2 implements AutoCloseable {
+
+ /**
+ * For parsing inside the system server but outside of {@link PackageManagerService}.
+ * Generally used for parsing information in an APK that hasn't been installed yet.
+ *
+ * This must be called inside the system process as it relies on {@link ServiceManager}.
+ */
+ public static PackageParser2 forParsingFileWithDefaults() {
+ PlatformCompat platformCompat =
+ (PlatformCompat) ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ return new PackageParser2(null /* separateProcesses */, false /* onlyCoreApps */,
+ null /* displayMetrics */, null /* cacheDir */, new Callback() {
+ @Override
+ public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
+ return platformCompat.isChangeEnabled(changeId, appInfo);
+ }
+
+ @Override
+ public boolean hasFeature(String feature) {
+ // Assume the device doesn't support anything. This will affect permission parsing
+ // and will force <uses-permission/> declarations to include all requiredNotFeature
+ // permissions and exclude all requiredFeature permissions. This mirrors the old
+ // behavior.
+ return false;
+ }
+ });
+ }
static final String TAG = "PackageParser2";
private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE;
private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100;
- private ThreadLocal<ParseTypeImpl> mSharedResult = ThreadLocal.withInitial(ParseTypeImpl::new);
+ private ThreadLocal<ApplicationInfo> mSharedAppInfo =
+ ThreadLocal.withInitial(() -> {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.uid = -1; // Not a valid UID since the app will not be installed yet
+ return appInfo;
+ });
- private final String[] mSeparateProcesses;
- private final boolean mOnlyCoreApps;
- private final DisplayMetrics mDisplayMetrics;
+ private ThreadLocal<ParseTypeImpl> mSharedResult;
@Nullable
protected PackageCacher mCacher;
@@ -64,27 +104,26 @@
* creating a minimalist boot environment.
*/
public PackageParser2(String[] separateProcesses, boolean onlyCoreApps,
- DisplayMetrics displayMetrics, @Nullable File cacheDir, Callback callback) {
- mSeparateProcesses = separateProcesses;
- mOnlyCoreApps = onlyCoreApps;
-
+ DisplayMetrics displayMetrics, @Nullable File cacheDir, @NonNull Callback callback) {
if (displayMetrics == null) {
- mDisplayMetrics = new DisplayMetrics();
- mDisplayMetrics.setToDefaults();
- } else {
- mDisplayMetrics = displayMetrics;
+ displayMetrics = new DisplayMetrics();
+ displayMetrics.setToDefaults();
}
mCacher = cacheDir == null ? null : new PackageCacher(cacheDir);
- // TODO(b/135203078): Remove nullability of callback
- callback = callback != null ? callback : new Callback() {
- @Override
- public boolean hasFeature(String feature) {
- return false;
- }
+
+ parsingUtils = new ParsingPackageUtils(onlyCoreApps, separateProcesses, displayMetrics,
+ callback);
+
+ ParseInput.Callback enforcementCallback = (changeId, packageName, targetSdkVersion) -> {
+ ApplicationInfo appInfo = mSharedAppInfo.get();
+ //noinspection ConstantConditions
+ appInfo.packageName = packageName;
+ appInfo.targetSdkVersion = targetSdkVersion;
+ return callback.isChangeEnabled(changeId, appInfo);
};
- parsingUtils = new ParsingPackageUtils(onlyCoreApps, separateProcesses, displayMetrics, callback);
+ mSharedResult = ThreadLocal.withInitial(() -> new ParseTypeImpl(enforcementCallback));
}
/**
@@ -126,13 +165,38 @@
return parsed;
}
+ /**
+ * Removes the cached value for the thread the parser was created on. It is assumed that
+ * any threads created for parallel parsing will be created and released, so they don't
+ * need an explicit close call.
+ *
+ * Realistically an instance should never be retained, so when the enclosing class is released,
+ * the values will also be released, making this method unnecessary.
+ */
+ @Override
+ public void close() {
+ mSharedResult.remove();
+ mSharedAppInfo.remove();
+ }
+
public static abstract class Callback implements ParsingPackageUtils.Callback {
@Override
- public final ParsingPackage startParsingPackage(String packageName, String baseCodePath,
- String codePath, TypedArray manifestArray, boolean isCoreApp) {
+ public final ParsingPackage startParsingPackage(@NonNull String packageName,
+ @NonNull String baseCodePath, @NonNull String codePath,
+ @NonNull TypedArray manifestArray, boolean isCoreApp) {
return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray,
isCoreApp);
}
+
+ /**
+ * An indirection from {@link ParseInput.Callback#isChangeEnabled(long, String, int)},
+ * allowing the {@link ApplicationInfo} objects to be cached in {@link #mSharedAppInfo}
+ * and cleaned up with the parser instance, not the callback instance.
+ *
+ * @param appInfo will only have 3 fields filled in, {@link ApplicationInfo#packageName},
+ * {@link ApplicationInfo#targetSdkVersion}, and {@link ApplicationInfo#uid}
+ */
+ public abstract boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo);
}
}
diff --git a/services/core/java/com/android/server/pm/parsing/ParsedComponentStateUtils.java b/services/core/java/com/android/server/pm/parsing/ParsedComponentStateUtils.java
new file mode 100644
index 0000000..54466ac
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/ParsedComponentStateUtils.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.parsing;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.parsing.component.ParsedComponent;
+import android.util.Pair;
+
+import com.android.server.pm.PackageSetting;
+
+/**
+ * For exposing internal fields to the rest of the server, enforcing that any overridden state from
+ * a {@link com.android.server.pm.PackageSetting} is applied.
+ *
+ * TODO(chiuwinson): The fields on ParsedComponent are not actually hidden. Will need to find a
+ * way to enforce the mechanism now that they exist in core instead of server. Can't rely on
+ * package-private.
+ *
+ * @hide
+ */
+public class ParsedComponentStateUtils {
+
+ @NonNull
+ public static Pair<CharSequence, Integer> getNonLocalizedLabelAndIcon(ParsedComponent component,
+ @Nullable PackageSetting pkgSetting, int userId) {
+ CharSequence label = component.getNonLocalizedLabel();
+ int icon = component.getIcon();
+
+ Pair<String, Integer> overrideLabelIcon = pkgSetting == null ? null :
+ pkgSetting.readUserState(userId)
+ .getOverrideLabelIconForComponent(component.getComponentName());
+ if (overrideLabelIcon != null) {
+ if (overrideLabelIcon.first != null) {
+ label = overrideLabelIcon.first;
+ }
+ if (overrideLabelIcon.second != null) {
+ icon = overrideLabelIcon.second;
+ }
+ }
+
+ return Pair.create(label, icon);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 82c02a4..b7c9ecb 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2497,10 +2497,24 @@
synchronized (mLock) {
ArraySet<String> newImplicitPermissions = new ArraySet<>();
+ // TODO ntmyren: Remove once propagated to droidfood
+ int flagMask = PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
+ | PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED;
+ int user = UserHandle.getUserId(pkg.getUid());
+
final int N = pkg.getRequestedPermissions().size();
for (int i = 0; i < N; i++) {
final String permName = pkg.getRequestedPermissions().get(i);
final BasePermission bp = mSettings.getPermissionLocked(permName);
+
+ // TODO ntmyren: Remove once propagated to droidfood
+ if (bp != null && !bp.isRuntime()) {
+ PermissionState permState = permissionsState.getInstallPermissionState(bp.name);
+ if (permState == null || (permState.getFlags() & flagMask) != 0) {
+ permissionsState.updatePermissionFlags(bp, user, flagMask, 0);
+ }
+ }
+
final boolean appSupportsRuntimePermissions =
pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
String upgradedActivityRecognitionPermission = null;
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 27288d8..161f304 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -30,7 +30,6 @@
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -48,7 +47,6 @@
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.permission.PermissionControllerManager;
-import android.provider.Settings;
import android.provider.Telephony;
import android.telecom.TelecomManager;
import android.util.ArrayMap;
@@ -72,9 +70,7 @@
import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ExecutionException;
/**
@@ -184,6 +180,8 @@
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addDataScheme("package");
+
+ /* TODO ntmyren: enable receiver when test flakes are fixed
getContext().registerReceiverAsUser(new BroadcastReceiver() {
final List<Integer> mUserSetupUids = new ArrayList<>(200);
final Map<UserHandle, PermissionControllerManager> mPermControllerManagers =
@@ -234,6 +232,7 @@
manager.updateUserSensitiveForApp(uid);
}
}, UserHandle.ALL, intentFilter, null, null);
+ */
}
/**
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java b/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
new file mode 100644
index 0000000..7977e93
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ExternalCaptureStateTracker.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import android.media.ICaptureStateListener;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.util.concurrent.Semaphore;
+import java.util.function.Consumer;
+
+/**
+ * This is a never-give-up listener for sound trigger external capture state notifications, as
+ * published by the audio policy service.
+ *
+ * This class will constantly try to connect to the service over a background thread and tolerate
+ * its death. The client will be notified by a single provided function that is called in a
+ * synchronized manner.
+ * For simplicity, there is currently no way to stop the tracker. This is possible to add if the
+ * need ever arises.
+ */
+class ExternalCaptureStateTracker {
+ private static final String TAG = "CaptureStateTracker";
+ /** Our client's listener. */
+ private final Consumer<Boolean> mListener;
+ /** This semaphore will get a permit every time we need to reconnect. */
+ private final Semaphore mNeedToConnect = new Semaphore(1);
+
+ /**
+ * Constructor. Will start a background thread to do the work.
+ *
+ * @param listener A client provided listener that will be called on state
+ * changes. May be
+ * called multiple consecutive times with the same value. Never
+ * called
+ * concurrently.
+ */
+ ExternalCaptureStateTracker(Consumer<Boolean> listener) {
+ mListener = listener;
+ new Thread(this::run).start();
+ }
+
+ /**
+ * Routine for the background thread. Keeps trying to reconnect.
+ */
+ private void run() {
+ while (true) {
+ mNeedToConnect.acquireUninterruptibly();
+ connect();
+ }
+ }
+
+ /**
+ * Connect to the service, install listener and death notifier.
+ */
+ private native void connect();
+
+ /**
+ * Called by native code to invoke the client listener.
+ *
+ * @param active true when external capture is active.
+ */
+ private void setCaptureState(boolean active) {
+ mListener.accept(active);
+ }
+
+ /**
+ * Called by native code when the remote service died.
+ */
+ private void binderDied() {
+ Log.w(TAG, "Audio policy service died");
+ mNeedToConnect.release();
+ }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
new file mode 100644
index 0000000..5def762
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ISoundTriggerMiddlewareInternal.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.soundtrigger_middleware;
+
+import android.media.ICaptureStateListener;
+import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
+
+/**
+ * This interface unifies ISoundTriggerMiddlewareService with ICaptureStateListener.
+ */
+public interface ISoundTriggerMiddlewareInternal extends ISoundTriggerMiddlewareService,
+ ICaptureStateListener {
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
index 9f4b09a..d76b1bf 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImpl.java
@@ -50,7 +50,7 @@
*
* @hide
*/
-public class SoundTriggerMiddlewareImpl implements ISoundTriggerMiddlewareService {
+public class SoundTriggerMiddlewareImpl implements ISoundTriggerMiddlewareInternal {
static private final String TAG = "SoundTriggerMiddlewareImpl";
private final SoundTriggerModule[] mModules;
@@ -124,7 +124,7 @@
}
@Override
- public void setExternalCaptureState(boolean active) {
+ public void setCaptureState(boolean active) {
for (SoundTriggerModule module : mModules) {
module.setExternalCaptureState(active);
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index fa78cb0..04ba6bf 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -62,11 +62,11 @@
* String, Object, Object[])}, {@link #logVoidReturnWithObject(Object, String, Object[])} and {@link
* #logExceptionWithObject(Object, String, Exception, Object[])}.
*/
-public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareService, Dumpable {
+public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInternal, Dumpable {
private static final String TAG = "SoundTriggerMiddlewareLogging";
- private final @NonNull ISoundTriggerMiddlewareService mDelegate;
+ private final @NonNull ISoundTriggerMiddlewareInternal mDelegate;
- public SoundTriggerMiddlewareLogging(@NonNull ISoundTriggerMiddlewareService delegate) {
+ public SoundTriggerMiddlewareLogging(@NonNull ISoundTriggerMiddlewareInternal delegate) {
mDelegate = delegate;
}
@@ -96,12 +96,12 @@
}
@Override
- public void setExternalCaptureState(boolean active) throws RemoteException {
+ public void setCaptureState(boolean active) throws RemoteException {
try {
- mDelegate.setExternalCaptureState(active);
- logVoidReturn("setExternalCaptureState", active);
+ mDelegate.setCaptureState(active);
+ logVoidReturn("setCaptureState", active);
} catch (Exception e) {
- logException("setExternalCaptureState", e, active);
+ logException("setCaptureState", e, active);
throw e;
}
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
index 0d8fc76..929d92f 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java
@@ -63,14 +63,21 @@
static private final String TAG = "SoundTriggerMiddlewareService";
@NonNull
- private final ISoundTriggerMiddlewareService mDelegate;
+ private final ISoundTriggerMiddlewareInternal mDelegate;
/**
* Constructor for internal use only. Could be exposed for testing purposes in the future.
* Users should access this class via {@link Lifecycle}.
*/
- private SoundTriggerMiddlewareService(@NonNull ISoundTriggerMiddlewareService delegate) {
+ private SoundTriggerMiddlewareService(@NonNull ISoundTriggerMiddlewareInternal delegate) {
mDelegate = Objects.requireNonNull(delegate);
+ new ExternalCaptureStateTracker(active -> {
+ try {
+ mDelegate.setCaptureState(active);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ });
}
@Override
@@ -86,11 +93,6 @@
return new ModuleService(mDelegate.attach(handle, callback));
}
- @Override
- public void setExternalCaptureState(boolean active) throws RemoteException {
- mDelegate.setExternalCaptureState(active);
- }
-
@Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
if (mDelegate instanceof Dumpable) {
((Dumpable) mDelegate).dump(fout);
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 06f2d65..008933f 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -105,7 +105,7 @@
*
* {@hide}
*/
-public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddlewareService, Dumpable {
+public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddlewareInternal, Dumpable {
private static final String TAG = "SoundTriggerMiddlewareValidation";
private enum ModuleState {
@@ -114,12 +114,12 @@
DEAD
};
- private final @NonNull ISoundTriggerMiddlewareService mDelegate;
+ private final @NonNull ISoundTriggerMiddlewareInternal mDelegate;
private final @NonNull Context mContext;
private Map<Integer, Set<ModuleService>> mModules;
public SoundTriggerMiddlewareValidation(
- @NonNull ISoundTriggerMiddlewareService delegate, @NonNull Context context) {
+ @NonNull ISoundTriggerMiddlewareInternal delegate, @NonNull Context context) {
mDelegate = delegate;
mContext = context;
}
@@ -213,21 +213,15 @@
}
@Override
- public void setExternalCaptureState(boolean active) {
- // Permission check.
- checkPreemptPermissions();
- // Input validation (always valid).
-
- // State validation (always valid).
-
+ public void setCaptureState(boolean active) {
+ // This is an internal call. No permissions needed.
+ //
// Normally, we would acquire a lock here. However, we do not access any state here so it
// is safe to not lock. This call is typically done from a different context than all the
// other calls and may result in a deadlock if we lock here (between the audio server and
// the system server).
-
- // From here on, every exception isn't client's fault.
try {
- mDelegate.setExternalCaptureState(active);
+ mDelegate.setCaptureState(active);
} catch (Exception e) {
throw handleException(e);
}
@@ -252,16 +246,6 @@
/**
* Throws a {@link SecurityException} if caller permanently doesn't have the given permission,
* or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if
- * caller temporarily doesn't have the right permissions to preempt active sound trigger
- * sessions.
- */
- void checkPreemptPermissions() {
- enforcePermission(Manifest.permission.PREEMPT_SOUND_TRIGGER);
- }
-
- /**
- * Throws a {@link SecurityException} if caller permanently doesn't have the given permission,
- * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if
* caller temporarily doesn't have the given permission.
*
* @param permission The permission to check.
@@ -806,4 +790,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 155b2e0..24ab89b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -29,6 +29,7 @@
import static android.util.MathUtils.abs;
import static android.util.MathUtils.constrain;
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
@@ -750,6 +751,7 @@
StatsEvent.Builder e = StatsEvent.newBuilder();
e.setAtomId(atomTag);
e.writeInt(entry.uid);
+ e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
if (withFgbg) {
e.writeInt(entry.set);
}
@@ -920,6 +922,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(traffic.getUid())
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeLong(traffic.getRxBytes())
.writeLong(traffic.getTxBytes())
.build();
@@ -1006,6 +1009,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeLong(userTimeUs)
.writeLong(systemTimeUs)
.build();
@@ -1036,6 +1040,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeInt(freqIndex)
.writeLong(cpuFreqTimeMs[freqIndex])
.build();
@@ -1066,6 +1071,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeLong(cpuActiveTimesMs)
.build();
pulledData.add(e);
@@ -1094,6 +1100,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeInt(i)
.writeLong(cpuClusterTimesMs[i])
.build();
@@ -1289,6 +1296,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(processMemoryState.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(processMemoryState.processName)
.writeInt(processMemoryState.oomScore)
.writeLong(memoryStat.pgfault)
@@ -1331,6 +1339,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(managedProcess.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(managedProcess.processName)
// RSS high-water mark in bytes.
.writeLong(snapshot.rssHighWaterMarkInKilobytes * 1024L)
@@ -1350,6 +1359,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(snapshot.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(processCmdlines.valueAt(i))
// RSS high-water mark in bytes.
.writeLong(snapshot.rssHighWaterMarkInKilobytes * 1024L)
@@ -1384,6 +1394,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(managedProcess.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(managedProcess.processName)
.writeInt(managedProcess.pid)
.writeInt(managedProcess.oomScore)
@@ -1409,6 +1420,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(snapshot.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(processCmdlines.valueAt(i))
.writeInt(pid)
.writeInt(-1001) // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.
@@ -1481,6 +1493,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(getUidForPid(allocations.pid))
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(readCmdlineFromProcfs(allocations.pid))
.writeInt((int) (allocations.totalSizeInBytes / 1024))
.writeInt(allocations.count)
@@ -1593,6 +1606,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(callStat.workSourceUid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(callStat.className)
.writeString(callStat.methodName)
.writeLong(callStat.callCount)
@@ -1669,6 +1683,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(entry.workSourceUid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(entry.handlerClassName)
.writeString(entry.threadName)
.writeString(entry.messageName)
@@ -2112,6 +2127,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeLong(fgCharsRead)
.writeLong(fgCharsWrite)
.writeLong(fgBytesRead)
@@ -2177,6 +2193,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(st.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(st.name)
.writeLong(st.base_utime)
.writeLong(st.base_stime)
@@ -2235,6 +2252,7 @@
StatsEvent.Builder e = StatsEvent.newBuilder();
e.setAtomId(atomTag);
e.writeInt(processCpuUsage.uid);
+ e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
e.writeInt(processCpuUsage.processId);
e.writeInt(threadCpuUsage.threadId);
e.writeString(processCpuUsage.processName);
@@ -2326,6 +2344,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(bs.uidObj.getUid())
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah))
.build();
pulledData.add(e);
@@ -2530,6 +2549,7 @@
StatsEvent e = StatsEvent.newBuilder()
.setAtomId(atomTag)
.writeInt(pkg.applicationInfo.uid)
+ .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
.writeString(holderName)
.writeString(roleName)
.build();
@@ -2613,6 +2633,7 @@
e.setAtomId(atomTag);
e.writeString(permName);
e.writeInt(pkg.applicationInfo.uid);
+ e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
if (atomTag == FrameworkStatsLog.DANGEROUS_PERMISSION_STATE) {
e.writeString("");
}
@@ -2967,6 +2988,7 @@
StatsEvent.Builder e = StatsEvent.newBuilder();
e.setAtomId(atomTag);
e.writeInt(uid);
+ e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
e.writeString(packageName);
if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
e.writeString(attributionTag);
@@ -3015,6 +3037,7 @@
StatsEvent.Builder e = StatsEvent.newBuilder();
e.setAtomId(atomTag);
e.writeInt(message.getUid());
+ e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
e.writeString(message.getPackageName());
e.writeString(message.getOp());
if (message.getAttributionTag() == null) {
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 0d16fcc..9a5b020 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -772,6 +772,8 @@
@NonNull
final TextClassifierServiceConnection mConnection;
final boolean mIsTrusted;
+ @Context.BindServiceFlags
+ final int mBindServiceFlags;
@NonNull
@GuardedBy("mLock")
final Queue<PendingRequest> mPendingRequests = new ArrayDeque<>();
@@ -786,11 +788,22 @@
@GuardedBy("mLock")
int mBoundServiceUid = Process.INVALID_UID;
- private ServiceState(@UserIdInt int userId, String packageName, boolean isTrusted) {
+ private ServiceState(
+ @UserIdInt int userId, @NonNull String packageName, boolean isTrusted) {
mUserId = userId;
mPackageName = packageName;
mConnection = new TextClassifierServiceConnection(mUserId);
mIsTrusted = isTrusted;
+ mBindServiceFlags = createBindServiceFlags(packageName);
+ }
+
+ @Context.BindServiceFlags
+ private int createBindServiceFlags(@NonNull String packageName) {
+ int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+ if (!packageName.equals(mDefaultTextClassifierPackage)) {
+ flags |= Context.BIND_RESTRICT_ASSOCIATIONS;
+ }
+ return flags;
}
@GuardedBy("mLock")
@@ -858,10 +871,7 @@
.setComponent(componentName);
Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent());
willBind = mContext.bindServiceAsUser(
- serviceIntent, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
- | Context.BIND_RESTRICT_ASSOCIATIONS,
- UserHandle.of(mUserId));
+ serviceIntent, mConnection, mBindServiceFlags, UserHandle.of(mUserId));
mBinding = willBind;
} finally {
Binder.restoreCallingIdentity(identity);
@@ -884,6 +894,7 @@
pw.printPair("packageName", mPackageName);
pw.printPair("boundComponentName", mBoundComponentName);
pw.printPair("isTrusted", mIsTrusted);
+ pw.printPair("bindServiceFlags", mBindServiceFlags);
pw.printPair("boundServiceUid", mBoundServiceUid);
pw.printPair("binding", mBinding);
pw.printPair("numberRequests", mPendingRequests.size());
diff --git a/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java b/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
index 8bd1035..165419a 100644
--- a/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
+++ b/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
@@ -22,7 +22,7 @@
import com.android.internal.util.IndentingPrintWriter;
-import java.util.LinkedList;
+import java.util.ArrayDeque;
/**
* A class that behaves like the following definition, except it stores the history of values set
@@ -50,11 +50,18 @@
*/
public final class ReferenceWithHistory<V> {
- /** The size the history linked list is allowed to grow to. */
+ private static final Object NULL_MARKER = "{null marker}";
+
+ /** The maximum number of references to store. */
private final int mMaxHistorySize;
+ /**
+ * The history storage. Note that ArrayDeque doesn't support {@code null} so this stores Object
+ * and not V. Use {@link #packNullIfRequired(Object)} and {@link #unpackNullIfRequired(Object)}
+ * to convert to / from the storage object.
+ */
@Nullable
- private LinkedList<V> mValues;
+ private ArrayDeque<Object> mValues;
/**
* Creates an instance that records, at most, the specified number of values.
@@ -69,22 +76,31 @@
/** Returns the current value, or {@code null} if it has never been set. */
@Nullable
public V get() {
- return (mValues == null || mValues.isEmpty()) ? null : mValues.getFirst();
+ if (mValues == null || mValues.isEmpty()) {
+ return null;
+ }
+ Object value = mValues.getFirst();
+ return unpackNullIfRequired(value);
}
- /** Sets the current value. Returns the previous value, or {@code null}. */
+ /**
+ * Sets the current value. Returns the previous value, which can be {@code null} if the
+ * reference has never been set, or if the reference has been set to {@code null}.
+ */
@Nullable
public V set(@Nullable V newValue) {
if (mValues == null) {
- mValues = new LinkedList<>();
+ mValues = new ArrayDeque<>(mMaxHistorySize);
+ }
+
+ if (mValues.size() >= mMaxHistorySize) {
+ mValues.removeLast();
}
V previous = get();
- mValues.addFirst(newValue);
- if (mValues.size() > mMaxHistorySize) {
- mValues.removeLast();
- }
+ Object nullSafeValue = packNullIfRequired(newValue);
+ mValues.addFirst(nullSafeValue);
return previous;
}
@@ -96,8 +112,8 @@
ipw.println("{Empty}");
} else {
int i = 0;
- for (V value : mValues) {
- ipw.println(i + ": " + value);
+ for (Object value : mValues) {
+ ipw.println(i + ": " + unpackNullIfRequired(value));
i++;
}
}
@@ -115,4 +131,23 @@
public String toString() {
return String.valueOf(get());
}
+
+ /**
+ * Turns a non-nullable Object into a nullable value. See also
+ * {@link #packNullIfRequired(Object)}.
+ */
+ @SuppressWarnings("unchecked")
+ @Nullable
+ private V unpackNullIfRequired(@NonNull Object value) {
+ return value == NULL_MARKER ? null : (V) value;
+ }
+
+ /**
+ * Turns a nullable value into a non-nullable Object. See also
+ * {@link #unpackNullIfRequired(Object)}.
+ */
+ @NonNull
+ private Object packNullIfRequired(@Nullable V value) {
+ return value == null ? NULL_MARKER : value;
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index ecafa69..c1c8440 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -36,6 +36,7 @@
import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
import static android.app.WaitResult.INVALID_DELAY;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
@@ -269,6 +270,8 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManager;
+import android.service.dreams.DreamActivity;
+import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
import android.util.EventLog;
@@ -2035,6 +2038,26 @@
return false;
}
+ static boolean canLaunchDreamActivity(String packageName) {
+ final DreamManagerInternal dreamManager =
+ LocalServices.getService(DreamManagerInternal.class);
+
+ // Verify that the package is the current active dream. The getActiveDreamComponent()
+ // call path does not acquire the DreamManager lock and thus is safe to use.
+ final ComponentName activeDream = dreamManager.getActiveDreamComponent(false /* doze */);
+ if (activeDream == null || activeDream.getPackageName() == null
+ || !activeDream.getPackageName().equals(packageName)) {
+ return false;
+ }
+
+ // Verify that the device is dreaming.
+ if (!LocalServices.getService(ActivityTaskManagerInternal.class).isDreaming()) {
+ return false;
+ }
+
+ return true;
+ }
+
private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent,
ActivityOptions options, ActivityRecord sourceRecord) {
int activityType = ACTIVITY_TYPE_UNDEFINED;
@@ -2054,6 +2077,10 @@
} else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
&& canLaunchAssistActivity(launchedFromPackage)) {
activityType = ACTIVITY_TYPE_ASSISTANT;
+ } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_DREAM
+ && canLaunchDreamActivity(launchedFromPackage)
+ && DreamActivity.class.getName() == info.name) {
+ activityType = ACTIVITY_TYPE_DREAM;
}
setActivityType(activityType);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0ba1866..7a6da67 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -341,7 +341,6 @@
int filterCallingUid;
PendingIntentRecord originatingPendingIntent;
boolean allowBackgroundActivityStart;
- boolean isDream;
/**
* If set to {@code true}, allows this activity start to look into
@@ -393,7 +392,6 @@
filterCallingUid = UserHandle.USER_NULL;
originatingPendingIntent = null;
allowBackgroundActivityStart = false;
- isDream = false;
}
/**
@@ -434,7 +432,6 @@
filterCallingUid = request.filterCallingUid;
originatingPendingIntent = request.originatingPendingIntent;
allowBackgroundActivityStart = request.allowBackgroundActivityStart;
- isDream = request.isDream;
}
/**
@@ -985,7 +982,7 @@
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart,
- request.isDream, intent);
+ intent);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
@@ -1195,7 +1192,7 @@
boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
final String callingPackage, int realCallingUid, int realCallingPid,
WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
- boolean allowBackgroundActivityStart, boolean isDream, Intent intent) {
+ boolean allowBackgroundActivityStart, Intent intent) {
// don't abort for the most important UIDs
final int callingAppId = UserHandle.getAppId(callingUid);
if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
@@ -1203,10 +1200,6 @@
return false;
}
- // don't abort if this is the dream activity
- if (isDream) {
- return false;
- }
// don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow =
@@ -2717,11 +2710,6 @@
return this;
}
- ActivityStarter setIsDream(boolean isDream) {
- mRequest.isDream = isDream;
- return this;
- }
-
void dump(PrintWriter pw, String prefix) {
prefix = prefix + " ";
pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 2263795..d48df9f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -290,6 +290,11 @@
public abstract void notifyActiveVoiceInteractionServiceChanged(ComponentName component);
/**
+ * Called when the device changes its dreaming state.
+ */
+ public abstract void notifyDreamStateChanged(boolean dreaming);
+
+ /**
* Set a uid that is allowed to bypass stopped app switches, launching an app
* whenever it wants.
*
@@ -318,6 +323,7 @@
public abstract void clearHeavyWeightProcessIfEquals(WindowProcessController proc);
public abstract void finishHeavyWeightApp();
+ public abstract boolean isDreaming();
public abstract boolean isSleeping();
public abstract boolean isShuttingDown();
public abstract boolean shuttingDown(boolean booted, int timeout);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 4fff860..682e991 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -212,7 +212,6 @@
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.dreams.DreamActivity;
-import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
import android.sysprop.DisplayProperties;
@@ -599,6 +598,13 @@
private boolean mSleeping = false;
/**
+ * The mDreaming state is set by the {@link DreamManagerService} when it receives a request to
+ * start/stop the dream. It is set to true shortly before the {@link DreamService} is started.
+ * It is set to false after the {@link DreamService} is stopped.
+ */
+ private boolean mDreaming = false;
+
+ /**
* The process state used for processes that are running the top activities.
* This changes between TOP and TOP_SLEEPING to following mSleeping.
*/
@@ -1238,36 +1244,29 @@
}
}
- @Override
- public boolean startDreamActivity(Intent intent) {
- final WindowProcessController process = mProcessMap.getProcess(Binder.getCallingPid());
+ private void enforceCallerIsDream(String callerPackageName) {
final long origId = Binder.clearCallingIdentity();
-
- // The dream activity is only called for non-doze dreams.
- final ComponentName currentDream = LocalServices.getService(DreamManagerInternal.class)
- .getActiveDreamComponent(/* doze= */ false);
-
- if (currentDream == null || currentDream.getPackageName() == null
- || !currentDream.getPackageName().equals(process.mInfo.packageName)) {
- Slog.e(TAG, "Calling package is not the current dream package. "
- + "Aborting startDreamActivity...");
- return false;
+ try {
+ if (!ActivityRecord.canLaunchDreamActivity(callerPackageName)) {
+ throw new SecurityException("The dream activity can be started only when the device"
+ + " is dreaming and only by the active dream package.");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
+ }
+
+ @Override
+ public boolean startDreamActivity(@NonNull Intent intent) {
+ assertPackageMatchesCallingUid(intent.getPackage());
+ enforceCallerIsDream(intent.getPackage());
final ActivityInfo a = new ActivityInfo();
a.theme = com.android.internal.R.style.Theme_Dream;
a.exported = true;
a.name = DreamActivity.class.getName();
-
-
- a.packageName = process.mInfo.packageName;
- a.applicationInfo = process.mInfo;
- a.processName = process.mInfo.processName;
- a.uiOptions = process.mInfo.uiOptions;
- a.taskAffinity = "android:" + a.packageName + "/dream";
a.enabled = true;
a.launchMode = ActivityInfo.LAUNCH_SINGLE_INSTANCE;
-
a.persistableMode = ActivityInfo.PERSIST_NEVER;
a.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
@@ -1276,15 +1275,34 @@
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchActivityType(ACTIVITY_TYPE_DREAM);
- try {
- getActivityStartController().obtainStarter(intent, "dream")
- .setActivityInfo(a)
- .setActivityOptions(options.toBundle())
- .setIsDream(true)
- .execute();
- return true;
- } finally {
- Binder.restoreCallingIdentity(origId);
+ synchronized (mGlobalLock) {
+ final WindowProcessController process = mProcessMap.getProcess(Binder.getCallingPid());
+
+ a.packageName = process.mInfo.packageName;
+ a.applicationInfo = process.mInfo;
+ a.processName = process.mInfo.processName;
+ a.uiOptions = process.mInfo.uiOptions;
+ a.taskAffinity = "android:" + a.packageName + "/dream";
+
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ getActivityStartController().obtainStarter(intent, "dream")
+ .setCallingUid(callingUid)
+ .setCallingPid(callingPid)
+ .setActivityInfo(a)
+ .setActivityOptions(options.toBundle())
+ // To start the dream from background, we need to start it from a persistent
+ // system process. Here we set the real calling uid to the system server uid
+ .setRealCallingUid(Binder.getCallingUid())
+ .setAllowBackgroundActivityStart(true)
+ .execute();
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
}
@@ -2476,7 +2494,7 @@
final ActivityStarter starter = getActivityStartController().obtainStarter(
null /* intent */, "moveTaskToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
- -1, callerApp, null, false, false, null)) {
+ -1, callerApp, null, false, null)) {
if (!isBackgroundActivityStartsEnabled()) {
return;
}
@@ -2784,7 +2802,8 @@
false /* includingParents */);
}
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(task.getStack().mRemoteToken, primarySplitTask.mRemoteToken, toTop);
+ wct.reparent(task.getStack().mRemoteToken.toWindowContainerToken(),
+ primarySplitTask.mRemoteToken.toWindowContainerToken(), toTop);
mWindowOrganizerController.applyTransaction(wct);
}
@@ -4273,7 +4292,7 @@
tempDockedTaskInsetBounds != null ? tempDockedTaskInsetBounds
: (tempDockedTaskBounds != null ? tempDockedTaskBounds
: dockedBounds);
- wct.setBounds(primary.mRemoteToken, primaryRect);
+ wct.setBounds(primary.mRemoteToken.toWindowContainerToken(), primaryRect);
Rect otherRect = tempOtherTaskInsetBounds != null ? tempOtherTaskInsetBounds
: tempOtherTaskBounds;
if (otherRect == null) {
@@ -4285,7 +4304,7 @@
otherRect.top = primaryRect.bottom + 6;
}
}
- wct.setBounds(secondary.mRemoteToken, otherRect);
+ wct.setBounds(secondary.mRemoteToken.toWindowContainerToken(), otherRect);
mWindowOrganizerController.applyTransaction(wct);
}
} finally {
@@ -6337,6 +6356,13 @@
}
@Override
+ public void notifyDreamStateChanged(boolean dreaming) {
+ synchronized (mGlobalLock) {
+ mDreaming = dreaming;
+ }
+ }
+
+ @Override
public void setAllowAppSwitches(@NonNull String type, int uid, int userId) {
if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_OR_STOPPED)) {
return;
@@ -6438,6 +6464,13 @@
}
}
+ @Override
+ public boolean isDreaming() {
+ synchronized (mGlobalLock) {
+ return mDreaming;
+ }
+ }
+
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public boolean isSleeping() {
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 4cce212..8fa8119 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -111,7 +111,7 @@
final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
null /* intent */, "moveToFront");
if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
- callingPackage, -1, -1, callerApp, null, false, false, null)) {
+ callingPackage, -1, -1, callerApp, null, false, null)) {
if (!mService.isBackgroundActivityStartsEnabled()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 5b20023..efcb558 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -16,10 +16,6 @@
package com.android.server.wm;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Slog;
-import android.window.ITaskOrganizer;
import android.view.SurfaceControl;
import java.util.HashMap;
@@ -50,7 +46,7 @@
private static final String TAG = "BLASTSyncEngine";
interface TransactionReadyListener {
- void transactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction);
+ void onTransactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction);
};
// Holds state associated with a single synchronous set of operations.
@@ -63,12 +59,12 @@
private void tryFinish() {
if (mRemainingTransactions == 0 && mReady) {
- mListener.transactionReady(mSyncId, mMergedTransaction);
+ mListener.onTransactionReady(mSyncId, mMergedTransaction);
mPendingSyncs.remove(mSyncId);
}
}
- public void transactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
+ public void onTransactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
mRemainingTransactions--;
mMergedTransaction.merge(mergedTransaction);
tryFinish();
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index fd70971..90fdf19 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -21,9 +21,9 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
-import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_ROOT;
-import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_UNDEFINED;
-import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS;
+import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
+import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
+import static android.window.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS;
import static com.android.internal.util.Preconditions.checkState;
import static com.android.server.wm.DisplayAreaProto.NAME;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 464b127..f05783b 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -94,7 +94,7 @@
void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) {
try {
- organizer.onDisplayAreaAppeared(da.mRemoteToken);
+ organizer.onDisplayAreaAppeared(da.mRemoteToken.toWindowContainerToken());
} catch (RemoteException e) {
// Oh well...
}
@@ -102,7 +102,7 @@
void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) {
try {
- organizer.onDisplayAreaVanished(da.mRemoteToken);
+ organizer.onDisplayAreaVanished(da.mRemoteToken.toWindowContainerToken());
} catch (RemoteException e) {
// Oh well...
}
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 950df6f..682a142 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -87,8 +87,8 @@
*
* Must be unique among the features added to a {@link DisplayAreaPolicyBuilder}.
*
- * @see android.window.WindowOrganizer.DisplayAreaOrganizer#FEATURE_SYSTEM_FIRST
- * @see android.window.WindowOrganizer.DisplayAreaOrganizer#FEATURE_VENDOR_FIRST
+ * @see android.window.DisplayAreaOrganizer#FEATURE_SYSTEM_FIRST
+ * @see android.window.DisplayAreaOrganizer#FEATURE_VENDOR_FIRST
*/
public int getId() {
return mId;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0108140..ce7e797 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -503,6 +503,9 @@
/** Windows removed since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */
final ArrayList<WindowState> mWinRemovedSinceNullFocus = new ArrayList<>();
+ /** Windows whose client's insets states are not up-to-date. */
+ final ArrayList<WindowState> mWinInsetsChanged = new ArrayList<>();
+
private ScreenRotationAnimation mScreenRotationAnimation;
/**
@@ -708,7 +711,10 @@
}
// Sets mBehindIme for each window. Windows behind IME can get IME insets.
- w.mBehindIme = mTmpWindowsBehindIme;
+ if (w.mBehindIme != mTmpWindowsBehindIme) {
+ w.mBehindIme = mTmpWindowsBehindIme;
+ mWinInsetsChanged.add(w);
+ }
if (w == mInputMethodWindow) {
mTmpWindowsBehindIme = true;
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index b2f5988..007af24 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -367,7 +367,6 @@
@Override
protected void onAnimationFinish() {
super.onAnimationFinish();
- mControlCallbacks.mAnimationControl.finish(mAnimatingShown);
DisplayThread.getHandler().post(mFinishCallback);
}
@@ -399,7 +398,7 @@
/** Called on SurfaceAnimationThread without global WM lock held. */
@Override
- public void scheduleApplyChangeInsets() {
+ public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) {
InsetsState state = getState();
if (mAnimationControl.applyChangeInsets(state)) {
mAnimationControl.finish(mAnimatingShown);
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 04454a5..ba14d48 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -227,10 +227,19 @@
for (int i = mProviders.size() - 1; i >= 0; i--) {
mProviders.valueAt(i).onPostLayout();
}
+ final ArrayList<WindowState> winInsetsChanged = mDisplayContent.mWinInsetsChanged;
if (!mLastState.equals(mState)) {
mLastState.set(mState, true /* copySources */);
notifyInsetsChanged();
+ } else {
+ // The global insets state has not changed but there might be windows whose conditions
+ // (e.g., z-order) have changed. They can affect the insets states that we dispatch to
+ // the clients.
+ for (int i = winInsetsChanged.size() - 1; i >= 0; i--) {
+ winInsetsChanged.get(i).notifyInsetsChanged();
+ }
}
+ winInsetsChanged.clear();
}
void onInsetsModified(InsetsControlTarget windowState, InsetsState state) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index af783c5..2764b12 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2346,7 +2346,7 @@
stack.getBounds(info.bounds);
info.displayId = taskDisplayArea != null ? taskDisplayArea.getDisplayId() : INVALID_DISPLAY;
info.stackId = stack.mTaskId;
- info.stackToken = stack.mRemoteToken;
+ info.stackToken = stack.mRemoteToken.toWindowContainerToken();
info.userId = stack.mCurrentUser;
info.visible = stack.shouldBeVisible(null);
// A stack might be not attached to a display.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9f5126e..0151b82 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -478,7 +478,7 @@
/**
* The TaskOrganizer which is delegated presentation of this task. If set the Task will
- * emit an IWindowContainer (allowing access to it's SurfaceControl leash) to the organizers
+ * emit an WindowContainerToken (allowing access to it's SurfaceControl leash) to the organizers
* taskAppeared callback, and emit a taskRemoved callback when the Task is vanished.
*/
ITaskOrganizer mTaskOrganizer;
@@ -3435,7 +3435,7 @@
info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
info.configuration.setTo(getConfiguration());
- info.token = mRemoteToken;
+ info.token = mRemoteToken.toWindowContainerToken();
//TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
// order changes.
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index a5ae721..9356ec2 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -31,7 +31,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_TASK_CONTAINER;
+import static android.window.DisplayAreaOrganizer.FEATURE_TASK_CONTAINER;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
@@ -1183,7 +1183,8 @@
for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
final Task root = mTmpTasks.get(i);
for (int j = 0; j < root.getChildCount(); j++) {
- wct.reparent(root.getChildAt(j).mRemoteToken, null, true /* toTop */);
+ wct.reparent(root.getChildAt(j).mRemoteToken.toWindowContainerToken(),
+ null, true /* toTop */);
}
}
mAtmService.mWindowOrganizerController.applyTransaction(wct);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 2dec655..872f254 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -36,7 +36,7 @@
import android.util.SparseArray;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
-import android.window.IWindowContainer;
+import android.window.WindowContainerToken;
import com.android.internal.util.ArrayUtils;
@@ -290,7 +290,7 @@
}
@Override
- public boolean deleteRootTask(IWindowContainer token) {
+ public boolean deleteRootTask(WindowContainerToken token) {
enforceStackPermission("deleteRootTask()");
final long origId = Binder.clearCallingIdentity();
try {
@@ -367,7 +367,7 @@
}
@Override
- public IWindowContainer getImeTarget(int displayId) {
+ public WindowContainerToken getImeTarget(int displayId) {
enforceStackPermission("getImeTarget()");
final long origId = Binder.clearCallingIdentity();
try {
@@ -382,7 +382,7 @@
if (task == null) {
return null;
}
- return task.getRootTask().mRemoteToken;
+ return task.getRootTask().mRemoteToken.toWindowContainerToken();
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -390,7 +390,7 @@
}
@Override
- public void setLaunchRoot(int displayId, @Nullable IWindowContainer token) {
+ public void setLaunchRoot(int displayId, @Nullable WindowContainerToken token) {
enforceStackPermission("setLaunchRoot()");
final long origId = Binder.clearCallingIdentity();
try {
@@ -422,7 +422,7 @@
}
@Override
- public List<RunningTaskInfo> getChildTasks(IWindowContainer parent,
+ public List<RunningTaskInfo> getChildTasks(WindowContainerToken parent,
@Nullable int[] activityTypes) {
enforceStackPermission("getChildTasks()");
final long ident = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 98585a9..58119c2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -76,7 +76,8 @@
import android.view.SurfaceSession;
import android.view.WindowManager;
import android.view.animation.Animation;
-import android.window.IWindowContainer;
+import android.window.IWindowContainerToken;
+import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
@@ -2449,8 +2450,10 @@
return RemoteToken.fromBinder(binder).getContainer();
}
- static class RemoteToken extends IWindowContainer.Stub {
+ static class RemoteToken extends IWindowContainerToken.Stub {
+
final WeakReference<WindowContainer> mWeakRef;
+ private WindowContainerToken mWindowContainerToken;
RemoteToken(WindowContainer container) {
mWeakRef = new WeakReference<>(container);
@@ -2476,6 +2479,13 @@
return sc;
}
+ WindowContainerToken toWindowContainerToken() {
+ if (mWindowContainerToken == null) {
+ mWindowContainerToken = new WindowContainerToken(this);
+ }
+ return mWindowContainerToken;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
@@ -2489,11 +2499,11 @@
}
@Override
- public void transactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
+ public void onTransactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
mergedTransaction.merge(mBLASTSyncTransaction);
mUsingBLASTSyncTransaction = false;
- mWaitingListener.transactionReady(mWaitingSyncId, mergedTransaction);
+ mWaitingListener.onTransactionReady(mWaitingSyncId, mergedTransaction);
mWaitingListener = null;
mWaitingSyncId = -1;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 14c9429..a332b69 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -340,12 +340,12 @@
}
@Override
- public void transactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
+ public void onTransactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) {
final IWindowContainerTransactionCallback callback =
mTransactionCallbacksByPendingSyncId.get(mSyncId);
try {
- callback.transactionReady(mSyncId, mergedTransaction);
+ callback.onTransactionReady(mSyncId, mergedTransaction);
} catch (RemoteException e) {
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8013a6c..7dcf375 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3427,53 +3427,38 @@
}
void reportResized() {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
+ if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
+ }
+
+ ProtoLog.v(WM_DEBUG_RESIZE, "Reporting new frame to %s: %s", this,
+ mWindowFrames.mCompatFrame);
+ if (mWinAnimator.mDrawState == DRAW_PENDING) {
+ ProtoLog.i(WM_DEBUG_ORIENTATION, "Resizing %s WITH DRAW PENDING", this);
+ }
+
+ getMergedConfiguration(mLastReportedConfiguration);
+ mLastConfigReportedToClient = true;
+
+ final Rect frame = mWindowFrames.mCompatFrame;
+ final Rect contentInsets = mWindowFrames.mLastContentInsets;
+ final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
+ final Rect stableInsets = mWindowFrames.mLastStableInsets;
+ final MergedConfiguration mergedConfiguration = mLastReportedConfiguration;
+ final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
+ final boolean forceRelayout = mReportOrientationChanged || isDragResizeChanged();
+ final int displayId = getDisplayId();
+ final DisplayCutout displayCutout = getWmDisplayCutout().getDisplayCutout();
+
try {
- ProtoLog.v(WM_DEBUG_RESIZE,
- "Reporting new frame to %s: %s", this,
- mWindowFrames.mCompatFrame);
- final MergedConfiguration mergedConfiguration =
- new MergedConfiguration(getProcessGlobalConfiguration(),
- getMergedOverrideConfiguration());
+ mClient.resized(frame, contentInsets, visibleInsets, stableInsets, reportDraw,
+ mergedConfiguration, getBackdropFrame(frame), forceRelayout,
+ getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this),
+ displayId, new DisplayCutout.ParcelableWrapper(displayCutout));
+ mDragResizingChangeReported = true;
- setLastReportedMergedConfiguration(mergedConfiguration);
-
- if (mWinAnimator.mDrawState == DRAW_PENDING) {
- ProtoLog.i(WM_DEBUG_ORIENTATION,
- "Resizing %s WITH DRAW PENDING", this);
- }
-
- final Rect frame = mWindowFrames.mCompatFrame;
- final Rect contentInsets = mWindowFrames.mLastContentInsets;
- final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
- final Rect stableInsets = mWindowFrames.mLastStableInsets;
- final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
- final boolean reportOrientation = mReportOrientationChanged;
- final int displayId = getDisplayId();
- final DisplayCutout displayCutout = getWmDisplayCutout().getDisplayCutout();
- if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
- && mClient instanceof IWindow.Stub) {
- // To prevent deadlock simulate one-way call if win.mClient is a local object.
- mWmService.mH.post(new Runnable() {
- @Override
- public void run() {
- try {
- dispatchResized(frame, contentInsets, visibleInsets,
- stableInsets, reportDraw, mergedConfiguration,
- reportOrientation, displayId, displayCutout);
- } catch (RemoteException e) {
- // Not a remote call, RemoteException won't be raised.
- }
- }
- });
- } else {
- dispatchResized(frame, contentInsets, visibleInsets, stableInsets,
- reportDraw, mergedConfiguration, reportOrientation, displayId,
- displayCutout);
- }
if (mWmService.mAccessibilityController != null) {
- mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(
- getDisplayId());
+ mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(displayId);
}
updateLocationInParentDisplayIfNeeded();
@@ -3603,20 +3588,6 @@
return stack.mTaskId;
}
- private void dispatchResized(Rect frame, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, boolean reportDraw,
- MergedConfiguration mergedConfiguration, boolean reportOrientation, int displayId,
- DisplayCutout displayCutout)
- throws RemoteException {
- final boolean forceRelayout = isDragResizeChanged() || reportOrientation;
-
- mClient.resized(frame, contentInsets, visibleInsets, stableInsets,
- reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
- getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this), displayId,
- new DisplayCutout.ParcelableWrapper(displayCutout));
- mDragResizingChangeReported = true;
- }
-
public void registerFocusObserver(IWindowFocusObserver observer) {
synchronized (mWmService.mGlobalLock) {
if (mFocusCallbacks == null) {
@@ -5752,7 +5723,7 @@
if (mLocalSyncId >= 0) {
mBLASTSyncEngine.setReady(mLocalSyncId);
} else {
- mWaitingListener.transactionReady(mWaitingSyncId, mBLASTSyncTransaction);
+ mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
}
mUsingBLASTSyncTransaction = false;
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 74982c6..4c3f73d 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -40,6 +40,7 @@
"com_android_server_security_VerityUtils.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",
+ "com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp",
"com_android_server_stats_pull_StatsPullAtomService.cpp",
"com_android_server_storage_AppFuseBridge.cpp",
"com_android_server_SystemServer.cpp",
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index e9a5e58..853eba7 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -392,6 +392,7 @@
mArgs = params.arguments();
mIfs = ifs;
mStatusListener = statusListener;
+ mIfs->setParams({.readLogsEnabled = true});
return true;
}
bool onStart() final { return true; }
@@ -438,7 +439,7 @@
}
const auto fileId = IncFs_FileIdFromMetadata(file.metadata);
- const auto incfsFd(mIfs->openWrite(fileId));
+ const base::unique_fd incfsFd(mIfs->openForSpecialOps(fileId).release());
if (incfsFd < 0) {
ALOGE("Failed to open an IncFS file for metadata: %.*s, final file name is: %s. "
"Error %d",
@@ -716,7 +717,7 @@
auto& writeFd = writeFds[fileIdx];
if (writeFd < 0) {
- writeFd.reset(this->mIfs->openWrite(fileId));
+ writeFd.reset(this->mIfs->openForSpecialOps(fileId).release());
if (writeFd < 0) {
ALOGE("Failed to open file %d for writing (%d). Aborting.", header.fileIdx,
-writeFd);
diff --git a/services/core/jni/com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp b/services/core/jni/com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp
new file mode 100644
index 0000000..ae6cb18
--- /dev/null
+++ b/services/core/jni/com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 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 <sstream>
+
+#define LOG_TAG "ExternalCaptureStateTracker"
+
+#include "core_jni_helpers.h"
+#include <log/log.h>
+#include <media/AudioSystem.h>
+
+namespace android {
+namespace {
+
+#define PACKAGE "com/android/server/soundtrigger_middleware"
+#define CLASSNAME PACKAGE "/ExternalCaptureStateTracker"
+
+jclass gExternalCaptureStateTrackerClassId;
+jmethodID gSetCaptureStateMethodId;
+jmethodID gBinderDiedMethodId;
+
+void PopulateIds(JNIEnv* env) {
+ gExternalCaptureStateTrackerClassId =
+ (jclass) env->NewGlobalRef(FindClassOrDie(env, CLASSNAME));
+ gSetCaptureStateMethodId = GetMethodIDOrDie(env,
+ gExternalCaptureStateTrackerClassId,
+ "setCaptureState",
+ "(Z)V");
+ gBinderDiedMethodId = GetMethodIDOrDie(env,
+ gExternalCaptureStateTrackerClassId,
+ "binderDied",
+ "()V");
+}
+
+class Listener : public AudioSystem::CaptureStateListener {
+public:
+ Listener(JNIEnv* env, jobject obj) : mObj(env->NewGlobalRef(obj)) {}
+
+ ~Listener() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mObj);
+ }
+
+ void onStateChanged(bool active) override {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mObj, gSetCaptureStateMethodId, active);
+ }
+
+ void onServiceDied() override {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mObj, gBinderDiedMethodId);
+ }
+
+private:
+ jobject mObj;
+};
+
+void connect(JNIEnv* env, jobject obj) {
+ sp<AudioSystem::CaptureStateListener> listener(new Listener(env, obj));
+ status_t status =
+ AudioSystem::registerSoundTriggerCaptureStateListener(listener);
+ LOG_ALWAYS_FATAL_IF(status != NO_ERROR);
+}
+
+const JNINativeMethod gMethods[] = {
+ {"connect", "()V", reinterpret_cast<void*>(connect)},
+};
+
+} // namespace
+
+int register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(
+ JNIEnv* env) {
+ PopulateIds(env);
+ return RegisterMethodsOrDie(env,
+ CLASSNAME,
+ gMethods,
+ NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index eb486fe..b988bd4 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -58,6 +58,8 @@
int register_android_server_am_LowMemDetector(JNIEnv* env);
int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
JNIEnv* env);
+int register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(
+ JNIEnv* env);
int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env);
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
int register_android_server_AdbDebuggingManager(JNIEnv* env);
@@ -112,6 +114,8 @@
register_android_server_am_LowMemDetector(env);
register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
env);
+ register_com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker(
+ env);
register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env);
register_android_server_stats_pull_StatsPullAtomService(env);
register_android_server_AdbDebuggingManager(env);
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 2dbbc5a..97de1800 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -155,6 +155,11 @@
return ok();
}
+binder::Status BinderIncrementalService::setStorageParams(int32_t storage, bool enableReadLogs, int32_t* _aidl_return) {
+ *_aidl_return = mImpl.setStorageParams(storage, enableReadLogs);
+ return ok();
+}
+
binder::Status BinderIncrementalService::makeDirectory(int32_t storageId, const std::string& path,
int32_t* _aidl_return) {
*_aidl_return = mImpl.makeDir(storageId, path);
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 28613e1..d0357d9 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -71,6 +71,7 @@
binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath,
const std::string& libDirRelativePath,
const std::string& abi, bool* _aidl_return) final;
+ binder::Status setStorageParams(int32_t storage, bool enableReadLogs, int32_t* _aidl_return) final;
private:
android::incremental::IncrementalService mImpl;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 25da8fe..5e3c337d 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -563,6 +563,36 @@
return it->second->second.storage;
}
+int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLogs) {
+ const auto ifs = getIfs(storageId);
+ if (!ifs) {
+ return -EINVAL;
+ }
+
+ using unique_fd = ::android::base::unique_fd;
+ ::android::os::incremental::IncrementalFileSystemControlParcel control;
+ control.cmd.reset(unique_fd(dup(ifs->control.cmd())));
+ control.pendingReads.reset(unique_fd(dup(ifs->control.pendingReads())));
+ auto logsFd = ifs->control.logs();
+ if (logsFd >= 0) {
+ control.log.reset(unique_fd(dup(logsFd)));
+ }
+
+ std::lock_guard l(mMountOperationLock);
+ const auto status = mVold->setIncFsMountOptions(control, enableReadLogs);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Calling Vold::setIncFsMountOptions() failed: " << status.toString8();
+ return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
+ ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode()
+ : status.serviceSpecificErrorCode() == 0
+ ? -EFAULT
+ : status.serviceSpecificErrorCode()
+ : -EIO;
+ }
+
+ return 0;
+}
+
void IncrementalService::deleteStorage(StorageId storageId) {
const auto ifs = getIfs(storageId);
if (!ifs) {
@@ -737,10 +767,12 @@
if (auto ifs = getIfs(storage)) {
std::string normPath = normalizePathToStorage(ifs, storage, path);
if (normPath.empty()) {
+ LOG(ERROR) << "Internal error: storageId " << storage << " failed to normalize: " << path;
return -EINVAL;
}
auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params);
if (err) {
+ LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile: " << err;
return err;
}
std::vector<uint8_t> metadataBytes;
@@ -1182,8 +1214,8 @@
success = false;
break;
}
- android::base::unique_fd writeFd(mIncFs->openWrite(ifs->control, libFileId));
- if (writeFd < 0) {
+ const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId);
+ if (!writeFd.ok()) {
LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
success = false;
break;
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 406b32e..90d58a7 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -111,6 +111,8 @@
int unbind(StorageId storage, std::string_view target);
void deleteStorage(StorageId storage);
+ int setStorageParams(StorageId storage, bool enableReadLogs);
+
int makeFile(StorageId storage, std::string_view path, int mode, FileId id,
incfs::NewFileParams params);
int makeDir(StorageId storage, std::string_view path, int mode = 0755);
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index c70a47d..c330030 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -49,6 +49,7 @@
virtual binder::Status unmountIncFs(const std::string& dir) const = 0;
virtual binder::Status bindMount(const std::string& sourceDir,
const std::string& targetDir) const = 0;
+ virtual binder::Status setIncFsMountOptions(const ::android::os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs) const = 0;
};
class DataLoaderManagerWrapper {
@@ -76,7 +77,7 @@
virtual ErrorCode link(const Control& control, std::string_view from,
std::string_view to) const = 0;
virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
- virtual base::unique_fd openWrite(const Control& control, FileId id) const = 0;
+ virtual base::unique_fd openForSpecialOps(const Control& control, FileId id) const = 0;
virtual ErrorCode writeBlocks(Span<const DataBlock> blocks) const = 0;
};
@@ -106,6 +107,9 @@
const std::string& targetDir) const override {
return mInterface->bindMount(sourceDir, targetDir);
}
+ binder::Status setIncFsMountOptions(const ::android::os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs) const override {
+ return mInterface->setIncFsMountOptions(control, enableReadLogs);
+ }
private:
sp<os::IVold> mInterface;
@@ -177,8 +181,8 @@
ErrorCode unlink(const Control& control, std::string_view path) const override {
return incfs::unlink(control, path);
}
- base::unique_fd openWrite(const Control& control, FileId id) const override {
- return base::unique_fd{incfs::openWrite(control, id)};
+ base::unique_fd openForSpecialOps(const Control& control, FileId id) const override {
+ return base::unique_fd{incfs::openForSpecialOps(control, id).release()};
}
ErrorCode writeBlocks(Span<const DataBlock> blocks) const override {
return incfs::writeBlocks(blocks);
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index c4b4d17..cde38fb 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -52,6 +52,8 @@
MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
MOCK_CONST_METHOD2(bindMount,
binder::Status(const std::string& sourceDir, const std::string& argetDir));
+ MOCK_CONST_METHOD2(setIncFsMountOptions,
+ binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&, bool));
void mountIncFsFails() {
ON_CALL(*this, mountIncFs(_, _, _, _))
@@ -74,6 +76,14 @@
void bindMountSuccess() {
ON_CALL(*this, bindMount(_, _)).WillByDefault(Return(binder::Status::ok()));
}
+ void setIncFsMountOptionsFails() const {
+ ON_CALL(*this, setIncFsMountOptions(_, _))
+ .WillByDefault(
+ Return(binder::Status::fromExceptionCode(1, String8("failed to set options"))));
+ }
+ void setIncFsMountOptionsSuccess() {
+ ON_CALL(*this, setIncFsMountOptions(_, _)).WillByDefault(Return(binder::Status::ok()));
+ }
binder::Status getInvalidControlParcel(const std::string& imagePath,
const std::string& targetDir, int32_t flags,
IncrementalFileSystemControlParcel* _aidl_return) {
@@ -175,7 +185,7 @@
MOCK_CONST_METHOD3(link,
ErrorCode(const Control& control, std::string_view from, std::string_view to));
MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
- MOCK_CONST_METHOD2(openWrite, base::unique_fd(const Control& control, FileId id));
+ MOCK_CONST_METHOD2(openForSpecialOps, base::unique_fd(const Control& control, FileId id));
MOCK_CONST_METHOD1(writeBlocks, ErrorCode(Span<const DataBlock> blocks));
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
@@ -390,6 +400,42 @@
ASSERT_TRUE(mIncrementalService->startLoading(storageId));
}
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mVold->setIncFsMountOptionsSuccess();
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, _));
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ ASSERT_GE(mIncrementalService->setStorageParams(storageId, true), 0);
+}
+
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mVold->setIncFsMountOptionsFails();
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, _));
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ ASSERT_LT(mIncrementalService->setStorageParams(storageId, true), 0);
+}
+
TEST_F(IncrementalServiceTest, testMakeDirectory) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
diff --git a/services/tests/PackageManagerComponentOverrideTests/Android.bp b/services/tests/PackageManagerComponentOverrideTests/Android.bp
new file mode 100644
index 0000000..a2668a1
--- /dev/null
+++ b/services/tests/PackageManagerComponentOverrideTests/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2019 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.
+//
+
+// NOTE: This test is separate from service tests since it relies on same vs different calling UID,
+// and this is more representative of a real caller. It also uses Mockito extended, and this
+// prevents converting the entire services test module.
+android_test {
+ name: "PackageManagerComponentOverrideTests",
+ srcs: [
+ "src/**/*.kt"
+ ],
+ static_libs: [
+ "androidx.test.runner",
+ "mockito-target-extended-minus-junit4",
+ "services.core",
+ "servicestests-utils-mockito-extended",
+ "testng", // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
+ "truth-prebuilt",
+ ],
+
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+ test_suites: ["device-tests"],
+ platform_apis: true,
+}
diff --git a/services/tests/PackageManagerComponentOverrideTests/AndroidManifest.xml b/services/tests/PackageManagerComponentOverrideTests/AndroidManifest.xml
new file mode 100644
index 0000000..c25e112
--- /dev/null
+++ b/services/tests/PackageManagerComponentOverrideTests/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.pm.test.override">
+
+ <uses-sdk
+ android:minSdkVersion="1"
+ android:targetSdkVersion="28" />
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.mock" android:required="true" />
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="PackageManagerComponentOverrideTests"
+ android:targetPackage="com.android.server.pm.test.override" />
+
+</manifest>
diff --git a/services/tests/PackageManagerComponentOverrideTests/AndroidTest.xml b/services/tests/PackageManagerComponentOverrideTests/AndroidTest.xml
new file mode 100644
index 0000000..b83b1a8
--- /dev/null
+++ b/services/tests/PackageManagerComponentOverrideTests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<configuration description="Test module config for PackageManagerComponentOverrideTests">
+ <option name="test-tag" value="PackageManagerComponentOverrideTests" />
+
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="PackageManagerComponentOverrideTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.server.pm.test.override" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/services/tests/PackageManagerComponentOverrideTests/res/drawable/black16x16.png b/services/tests/PackageManagerComponentOverrideTests/res/drawable/black16x16.png
new file mode 100644
index 0000000..86b12fc
--- /dev/null
+++ b/services/tests/PackageManagerComponentOverrideTests/res/drawable/black16x16.png
Binary files differ
diff --git a/services/tests/PackageManagerComponentOverrideTests/res/drawable/white16x16.png b/services/tests/PackageManagerComponentOverrideTests/res/drawable/white16x16.png
new file mode 100644
index 0000000..49dbb4f
--- /dev/null
+++ b/services/tests/PackageManagerComponentOverrideTests/res/drawable/white16x16.png
Binary files differ
diff --git a/services/tests/PackageManagerComponentOverrideTests/res/values/values.xml b/services/tests/PackageManagerComponentOverrideTests/res/values/values.xml
new file mode 100644
index 0000000..73d1128
--- /dev/null
+++ b/services/tests/PackageManagerComponentOverrideTests/res/values/values.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <public name="black16x16" type="drawable" id="0x7f080001"/>
+ <public name="white16x16" type="drawable" id="0x7f080002"/>
+</resources>
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
new file mode 100644
index 0000000..ecdb30f
--- /dev/null
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.override
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.parsing.component.ParsedActivity
+import android.os.Binder
+import android.os.UserHandle
+import android.util.ArrayMap
+import com.android.server.pm.AppsFilter
+import com.android.server.pm.ComponentResolver
+import com.android.server.pm.PackageManagerService
+import com.android.server.pm.PackageSetting
+import com.android.server.pm.Settings
+import com.android.server.pm.UserManagerService
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.server.pm.parsing.pkg.ParsedPackage
+import com.android.server.pm.permission.PermissionManagerServiceInternal
+import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverrideTest.Companion.Params.AppType
+import com.android.server.pm.test.override.R
+import com.android.server.testutils.TestHandler
+import com.android.server.testutils.mock
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.spy
+import com.android.server.testutils.whenever
+import com.android.server.wm.ActivityTaskManagerInternal
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.intThat
+import org.mockito.Mockito.never
+import org.mockito.Mockito.same
+import org.mockito.Mockito.verify
+import org.testng.Assert.assertThrows
+import java.io.File
+
+@RunWith(Parameterized::class)
+class PackageManagerComponentLabelIconOverrideTest {
+
+ companion object {
+ private const val VALID_PKG = "com.android.server.pm.test.override"
+ private const val SHARED_PKG = "com.android.server.pm.test.override.shared"
+ private const val INVALID_PKG = "com.android.server.pm.test.override.invalid"
+
+ private const val SEND_PENDING_BROADCAST = 1 // PackageManagerService.SEND_PENDING_BROADCAST
+
+ private const val DEFAULT_LABEL = "DefaultLabel"
+ private const val TEST_LABEL = "TestLabel"
+
+ private const val DEFAULT_ICON = R.drawable.black16x16
+ private const val TEST_ICON = R.drawable.white16x16
+
+ private const val COMPONENT_CLASS_NAME = ".TestComponent"
+
+ sealed class Result {
+ // Component label/icon changed, message sent to send broadcast
+ object Changed : Result()
+
+ // Component label/icon changed, message was pending, not re-sent
+ object ChangedWithoutNotify : Result()
+
+ // Component label/icon did not changed, was already equivalent
+ object NotChanged : Result()
+
+ // Updating label/icon encountered a specific exception
+ data class Exception(val type: Class<out java.lang.Exception>) : Result()
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun parameters() = arrayOf(
+ // Start with an array of the simplest known inputs and expected outputs
+ Params(VALID_PKG, AppType.SYSTEM_APP, Result.Changed),
+ Params(SHARED_PKG, AppType.SYSTEM_APP, Result.Changed),
+ Params(INVALID_PKG, AppType.SYSTEM_APP, SecurityException::class.java)
+ )
+ .flatMap { param ->
+ mutableListOf(param).apply {
+ if (param.result is Result.Changed) {
+ // For each param that would've succeeded, also verify that if a change
+ // happened, but a message was pending, another is not re-queued/reset
+ this += param.copy(result = Result.ChangedWithoutNotify)
+ // Also verify that when the component is already configured, no change
+ // is propagated
+ this += param.copy(result = Result.NotChanged)
+ }
+ // For all params, verify that an invalid component will cause an
+ // IllegalArgumentException, instead of result initially specified
+ this += param.copy(componentName = null,
+ result = Result.Exception(IllegalArgumentException::class.java))
+ // Also verify an updated system app variant, which should have the same
+ // result as a vanilla system app
+ this += param.copy(appType = AppType.UPDATED_SYSTEM_APP)
+ // Also verify a non-system app will cause a failure, since normal apps
+ // are not allowed to edit their label/icon
+ this += param.copy(appType = AppType.NORMAL_APP,
+ result = Result.Exception(SecurityException::class.java))
+ }
+ }
+
+ data class Params(
+ val pkgName: String,
+ private val appType: AppType,
+ val result: Result,
+ val componentName: ComponentName? = ComponentName(pkgName, COMPONENT_CLASS_NAME)
+ ) {
+ constructor(pkgName: String, appType: AppType, exception: Class<out Exception>)
+ : this(pkgName, appType, Result.Exception(exception))
+
+ val expectedLabel = when (result) {
+ Result.Changed, Result.ChangedWithoutNotify, Result.NotChanged -> TEST_LABEL
+ is Result.Exception -> DEFAULT_LABEL
+ }
+
+ val expectedIcon = when (result) {
+ Result.Changed, Result.ChangedWithoutNotify, Result.NotChanged -> TEST_ICON
+ is Result.Exception -> DEFAULT_ICON
+ }
+
+ val isUpdatedSystemApp = appType == AppType.UPDATED_SYSTEM_APP
+ val isSystem = appType == AppType.SYSTEM_APP || isUpdatedSystemApp
+
+ override fun toString(): String {
+ val resultString = when (result) {
+ Result.Changed -> "Changed"
+ Result.ChangedWithoutNotify -> "ChangedWithoutNotify"
+ Result.NotChanged -> "NotChanged"
+ is Result.Exception -> result.type.simpleName
+ }
+
+ // Nicer formatting for the test method suffix
+ return "pkg=$pkgName, type=$appType, component=$componentName, result=$resultString"
+ }
+
+ enum class AppType { SYSTEM_APP, UPDATED_SYSTEM_APP, NORMAL_APP }
+ }
+ }
+
+ @Parameterized.Parameter(0)
+ lateinit var params: Params
+
+ private lateinit var testHandler: TestHandler
+ private lateinit var mockPendingBroadcasts: PackageManagerService.PendingPackageBroadcasts
+ private lateinit var mockPkg: AndroidPackage
+ private lateinit var mockPkgSetting: PackageSetting
+ private lateinit var service: PackageManagerService
+
+ private val userId = UserHandle.getCallingUserId()
+ private val userIdDifferent = userId + 1
+
+ @Before
+ fun setUpMocks() {
+ makeTestData()
+
+ testHandler = TestHandler(null)
+ if (params.result is Result.ChangedWithoutNotify) {
+ // Case where the handler already has a message and so another should not be sent.
+ // This case will verify that only 1 message exists, which is the one added here.
+ testHandler.sendEmptyMessage(SEND_PENDING_BROADCAST)
+ }
+
+ mockPendingBroadcasts = PackageManagerService.PendingPackageBroadcasts()
+
+ service = mockService()
+ }
+
+ @Test
+ fun updateComponentLabelIcon() {
+ fun runUpdate() {
+ service.updateComponentLabelIcon(params.componentName, TEST_LABEL, TEST_ICON, userId)
+ }
+
+ when (val result = params.result) {
+ Result.Changed, Result.ChangedWithoutNotify, Result.NotChanged -> {
+ runUpdate()
+ verify(mockPkgSetting).overrideNonLocalizedLabelAndIcon(params.componentName!!,
+ TEST_LABEL, TEST_ICON, userId)
+ }
+ is Result.Exception -> {
+ assertThrows(result.type) { runUpdate() }
+ verify(mockPkgSetting, never()).overrideNonLocalizedLabelAndIcon(
+ any<ComponentName>(), any(), anyInt(), anyInt())
+ }
+ }
+ }
+
+ @After
+ fun verifyExpectedResult() {
+ if (params.componentName != null) {
+ val activityInfo = service.getActivityInfo(params.componentName, 0, userId)
+ assertThat(activityInfo.nonLocalizedLabel).isEqualTo(params.expectedLabel)
+ assertThat(activityInfo.icon).isEqualTo(params.expectedIcon)
+ }
+ }
+
+ @After
+ fun verifyDifferentUserUnchanged() {
+ when (params.result) {
+ Result.Changed, Result.ChangedWithoutNotify -> {
+ val activityInfo = service.getActivityInfo(params.componentName, 0, userIdDifferent)
+ assertThat(activityInfo.nonLocalizedLabel).isEqualTo(DEFAULT_LABEL)
+ assertThat(activityInfo.icon).isEqualTo(DEFAULT_ICON)
+ }
+ Result.NotChanged, is Result.Exception -> {}
+ }.run { /*exhaust*/ }
+ }
+
+ @After
+ fun verifyHandlerHasMessage() {
+ when (params.result) {
+ is Result.Changed, is Result.ChangedWithoutNotify -> {
+ assertThat(testHandler.pendingMessages).hasSize(1)
+ assertThat(testHandler.pendingMessages.first().message.what)
+ .isEqualTo(SEND_PENDING_BROADCAST)
+ }
+ is Result.NotChanged, is Result.Exception -> {
+ assertThat(testHandler.pendingMessages).hasSize(0)
+ }
+ }.run { /*exhaust*/ }
+ }
+
+ @After
+ fun verifyPendingBroadcast() {
+ when (params.result) {
+ is Result.Changed, Result.ChangedWithoutNotify -> {
+ assertThat(mockPendingBroadcasts.get(userId, params.pkgName))
+ .containsExactly(params.componentName!!.className)
+ .inOrder()
+ }
+ is Result.NotChanged, is Result.Exception -> {
+ assertThat(mockPendingBroadcasts.get(userId, params.pkgName)).isNull()
+ }
+ }.run { /*exhaust*/ }
+ }
+
+ private fun makePkg(pkgName: String, block: ParsedPackage.() -> Unit = {}) =
+ PackageImpl.forTesting(pkgName)
+ .setEnabled(true)
+ .let { it.hideAsParsed() as ParsedPackage }
+ .setSystem(params.isSystem)
+ .apply(block)
+ .hideAsFinal()
+
+ private fun makePkgSetting(pkgName: String) = spy(PackageSetting(pkgName, null, File("/test"),
+ File("/test"), null, null, null, null, 0, 0, 0, 0, null, null, null)) {
+ this.pkgState.isUpdatedSystemApp = params.isUpdatedSystemApp
+ }
+
+ private fun makeTestData() {
+ mockPkg = makePkg(params.pkgName)
+ mockPkgSetting = makePkgSetting(params.pkgName)
+
+ if (params.result is Result.NotChanged) {
+ // If verifying no-op behavior, set the current setting to the test values
+ mockPkgSetting.overrideNonLocalizedLabelAndIcon(params.componentName!!, TEST_LABEL,
+ TEST_ICON, userId)
+ // Then clear the mock because the line above just incremented it
+ clearInvocations(mockPkgSetting)
+ }
+ }
+
+ private fun mockService(): PackageManagerService {
+ val mockedPkgs = mapOf(
+ // Must use the test app's UID so that PMS can match them when querying, since
+ // the static Binder.getCallingUid can't mocked as it's marked final
+ VALID_PKG to makePkg(VALID_PKG) { uid = Binder.getCallingUid() },
+ SHARED_PKG to makePkg(SHARED_PKG) { uid = Binder.getCallingUid() },
+ INVALID_PKG to makePkg(INVALID_PKG) { uid = Binder.getCallingUid() + 1 }
+ )
+ val mockedPkgSettings = mapOf(
+ VALID_PKG to makePkgSetting(VALID_PKG),
+ SHARED_PKG to makePkgSetting(SHARED_PKG),
+ INVALID_PKG to makePkgSetting(INVALID_PKG)
+ )
+ // Add pkgSetting under test so its attributes override the defaults added above
+ .plus(params.pkgName to mockPkgSetting)
+
+ val mockActivity: ParsedActivity = mock {
+ whenever(this.packageName) { params.pkgName }
+ whenever(this.nonLocalizedLabel) { DEFAULT_LABEL }
+ whenever(this.icon) { DEFAULT_ICON }
+ whenever(this.componentName) { params.componentName }
+ whenever(this.name) { params.componentName?.className }
+ whenever(this.isEnabled) { true }
+ whenever(this.isDirectBootAware) { params.isSystem }
+ }
+
+ val mockSettings = Settings(mockedPkgSettings)
+ val mockComponentResolver: ComponentResolver = mockThrowOnUnmocked {
+ params.componentName?.let {
+ whenever(this.componentExists(same(it))) { true }
+ whenever(this.getActivity(same(it))) { mockActivity }
+ }
+ }
+ val mockUserManagerService: UserManagerService = mockThrowOnUnmocked {
+ val matcher: (Int) -> Boolean = { it == userId || it == userIdDifferent }
+ whenever(this.exists(intThat(matcher))) { true }
+ whenever(this.isUserUnlockingOrUnlocked(intThat(matcher))) { true }
+ }
+ val mockPermissionManagerService: PermissionManagerServiceInternal = mockThrowOnUnmocked {
+ whenever(this.enforceCrossUserPermission(anyInt(), anyInt(), anyBoolean(), anyBoolean(),
+ anyString())) { }
+ }
+ val mockActivityTaskManager: ActivityTaskManagerInternal = mockThrowOnUnmocked {
+ whenever(this.isCallerRecents(anyInt())) { false }
+ }
+ val mockAppsFilter: AppsFilter = mockThrowOnUnmocked {
+ whenever(this.shouldFilterApplication(anyInt(), any<PackageSetting>(),
+ any<PackageSetting>(), anyInt())) { false }
+ }
+ val mockContext: Context = mockThrowOnUnmocked {
+ whenever(this.getString(
+ com.android.internal.R.string.config_overrideComponentUiPackage)) { VALID_PKG }
+ }
+ val mockInjector: PackageManagerService.Injector = mock {
+ whenever(this.lock) { Object() }
+ whenever(this.componentResolver) { mockComponentResolver }
+ whenever(this.userManagerService) { mockUserManagerService }
+ whenever(this.permissionManagerServiceInternal) { mockPermissionManagerService }
+ whenever(this.settings) { mockSettings }
+ whenever(this.activityTaskManagerInternal) { mockActivityTaskManager }
+ whenever(this.appsFilter) { mockAppsFilter }
+ whenever(this.context) { mockContext }
+ }
+ val testParams = PackageManagerService.TestParams().apply {
+ this.handler = testHandler
+ this.pendingPackageBroadcasts = mockPendingBroadcasts
+ this.resolveComponentName = ComponentName("android", ".Test")
+ this.packages = ArrayMap<String, AndroidPackage>().apply { putAll(mockedPkgs) }
+ }
+
+ return PackageManagerService(mockInjector, testParams)
+ }
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index e58e911..b457856 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -107,6 +107,8 @@
name: "servicestests-utils",
srcs: [
"utils/**/*.java",
+ "utils/**/*.kt",
+ "utils-mockito/**/*.kt",
],
static_libs: [
"junit",
@@ -117,6 +119,22 @@
],
}
+java_library {
+ name: "servicestests-utils-mockito-extended",
+ srcs: [
+ "utils/**/*.java",
+ "utils/**/*.kt",
+ "utils-mockito/**/*.kt",
+ ],
+ static_libs: [
+ "junit",
+ "mockito-target-extended-minus-junit4",
+ ],
+ libs: [
+ "android.test.runner",
+ ],
+}
+
filegroup {
name: "servicestests-SuspendTestApp-files",
srcs: [
diff --git a/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyActionSdkQ.apk b/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyActionSdkQ.apk
new file mode 100644
index 0000000..841fceb
--- /dev/null
+++ b/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyActionSdkQ.apk
Binary files differ
diff --git a/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyActionSdkR.apk b/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyActionSdkR.apk
new file mode 100644
index 0000000..3520650
--- /dev/null
+++ b/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyActionSdkR.apk
Binary files differ
diff --git a/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyCategorySdkQ.apk b/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyCategorySdkQ.apk
new file mode 100644
index 0000000..6774d5f
--- /dev/null
+++ b/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyCategorySdkQ.apk
Binary files differ
diff --git a/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyCategorySdkR.apk b/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyCategorySdkR.apk
new file mode 100644
index 0000000..23efb19
--- /dev/null
+++ b/services/tests/servicestests/res/raw/PackageParsingTestAppEmptyCategorySdkR.apk
Binary files differ
diff --git a/services/tests/servicestests/res/raw/PackageParsingTestAppMissingAppSdkQ.apk b/services/tests/servicestests/res/raw/PackageParsingTestAppMissingAppSdkQ.apk
new file mode 100644
index 0000000..f684f86
--- /dev/null
+++ b/services/tests/servicestests/res/raw/PackageParsingTestAppMissingAppSdkQ.apk
Binary files differ
diff --git a/services/tests/servicestests/res/raw/PackageParsingTestAppMissingAppSdkR.apk b/services/tests/servicestests/res/raw/PackageParsingTestAppMissingAppSdkR.apk
new file mode 100644
index 0000000..491c56c
--- /dev/null
+++ b/services/tests/servicestests/res/raw/PackageParsingTestAppMissingAppSdkR.apk
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index d3a3e7e..e5741ee 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -67,8 +67,11 @@
import androidx.test.InstrumentationRegistry;
import com.android.internal.R;
+import com.android.server.compat.PlatformCompat;
import com.android.server.integrity.engine.RuleEvaluationEngine;
import com.android.server.integrity.model.IntegrityCheckResult;
+import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.testutils.TestUtils;
import org.junit.After;
@@ -88,6 +91,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.function.Supplier;
/** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */
@RunWith(JUnit4.class)
@@ -131,12 +135,15 @@
@org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock PackageManagerInternal mPackageManagerInternal;
+ @Mock PlatformCompat mPlatformCompat;
@Mock Context mMockContext;
@Mock Resources mMockResources;
@Mock RuleEvaluationEngine mRuleEvaluationEngine;
@Mock IntegrityFileManager mIntegrityFileManager;
@Mock Handler mHandler;
+ private Supplier<PackageParser2> mParserSupplier = TestPackageParser2::new;
+
private final Context mRealContext = InstrumentationRegistry.getTargetContext();
private PackageManager mSpyPackageManager;
@@ -168,6 +175,7 @@
new AppIntegrityManagerServiceImpl(
mMockContext,
mPackageManagerInternal,
+ mParserSupplier,
mRuleEvaluationEngine,
mIntegrityFileManager,
mHandler);
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
index 063cd5da..78c7080 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -18,6 +18,8 @@
import android.net.Uri
import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 73e5b6d..3718c5c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -46,6 +46,7 @@
import com.android.frameworks.servicestests.R;
import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.TestPackageParser2;
import org.junit.Before;
import org.junit.Test;
@@ -77,7 +78,7 @@
ApexManager.ApexManagerImpl managerImpl = spy(new ApexManager.ApexManagerImpl());
doReturn(mApexService).when(managerImpl).waitForApexService();
mApexManager = managerImpl;
- mPackageParser2 = new PackageParser2(null, false, null, null, null);
+ mPackageParser2 = new TestPackageParser2();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index d760629..daaf870 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -49,7 +49,6 @@
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
-import android.util.DisplayMetrics;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
@@ -61,6 +60,7 @@
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -108,7 +108,7 @@
@Test
public void testParse_noCache() throws Exception {
- CachePackageNameParser pp = new CachePackageNameParser(null, false, null, null, null);
+ CachePackageNameParser pp = new CachePackageNameParser(null);
ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
false /* useCaches */);
assertNotNull(pkg);
@@ -125,7 +125,7 @@
@Test
public void testParse_withCache() throws Exception {
- CachePackageNameParser pp = new CachePackageNameParser(null, false, null, null, null);
+ CachePackageNameParser pp = new CachePackageNameParser(null);
pp.setCacheDir(mTmpDir);
// The first parse will write this package to the cache.
@@ -144,7 +144,7 @@
// We haven't set a cache directory here : the parse should still succeed,
// just not using the cached results.
- pp = new CachePackageNameParser(null, false, null, null, null);
+ pp = new CachePackageNameParser(null);
pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */);
assertEquals("android", pkg.getPackageName());
@@ -154,17 +154,29 @@
@Test
public void test_serializePackage() throws Exception {
- PackageParser2 pp = new PackageParser2(null, false, null, mTmpDir, null);
- ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
- true /* useCaches */);
+ try (PackageParser2 pp = new PackageParser2(null, false, null, mTmpDir,
+ new PackageParser2.Callback() {
+ @Override
+ public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
+ return true;
+ }
- Parcel p = Parcel.obtain();
- pkg.writeToParcel(p, 0 /* flags */);
+ @Override
+ public boolean hasFeature(String feature) {
+ return false;
+ }
+ })) {
+ ParsedPackage pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */,
+ true /* useCaches */);
- p.setDataPosition(0);
- ParsedPackage deserialized = new PackageImpl(p);
+ Parcel p = Parcel.obtain();
+ pkg.writeToParcel(p, 0 /* flags */);
- assertPackagesEqual(pkg, deserialized);
+ p.setDataPosition(0);
+ ParsedPackage deserialized = new PackageImpl(p);
+
+ assertPackagesEqual(pkg, deserialized);
+ }
}
@Test
@@ -218,10 +230,6 @@
assertSame(deserialized.getSharedUserId(), deserialized2.getSharedUserId());
}
- private static PackageParser2 makeParser() {
- return new PackageParser2(null, false, null, null, null);
- }
-
private File extractFile(String filename) throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
final File tmpFile = File.createTempFile(filename, ".apk");
@@ -238,7 +246,7 @@
public void testParseIsolatedSplitsDefault() throws Exception {
final File testFile = extractFile(TEST_APP1_APK);
try {
- final ParsedPackage pkg = makeParser().parsePackage(testFile, 0, false);
+ final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
assertFalse("isolatedSplits", pkg.isIsolatedSplitLoading());
} finally {
testFile.delete();
@@ -252,7 +260,7 @@
public void testParseIsolatedSplitsConstant() throws Exception {
final File testFile = extractFile(TEST_APP2_APK);
try {
- final ParsedPackage pkg = makeParser().parsePackage(testFile, 0, false);
+ final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
assertTrue("isolatedSplits", pkg.isIsolatedSplitLoading());
} finally {
testFile.delete();
@@ -266,7 +274,7 @@
public void testParseIsolatedSplitsResource() throws Exception {
final File testFile = extractFile(TEST_APP3_APK);
try {
- final ParsedPackage pkg = makeParser().parsePackage(testFile, 0, false);
+ final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
assertTrue("isolatedSplits", pkg.isIsolatedSplitLoading());
} finally {
testFile.delete();
@@ -279,10 +287,18 @@
*/
public static class CachePackageNameParser extends PackageParser2 {
- CachePackageNameParser(String[] separateProcesses, boolean onlyCoreApps,
- DisplayMetrics displayMetrics, @Nullable File cacheDir,
- PackageParser2.Callback callback) {
- super(separateProcesses, onlyCoreApps, displayMetrics, cacheDir, callback);
+ CachePackageNameParser(@Nullable File cacheDir) {
+ super(null, false, null, null, new Callback() {
+ @Override
+ public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
+ return true;
+ }
+
+ @Override
+ public boolean hasFeature(String feature) {
+ return false;
+ }
+ });
if (cacheDir != null) {
setCacheDir(cacheDir);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index 9d3ac17..38d01d0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -16,13 +16,13 @@
package com.android.server.pm;
-import android.content.pm.PackageParser;
import android.platform.test.annotations.Presubmit;
import android.util.Log;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import junit.framework.Assert;
@@ -48,7 +48,7 @@
@Before
public void setUp() {
- mParser = new TestParallelPackageParser(new PackageParser2(null, false, null, null, null),
+ mParser = new TestParallelPackageParser(new TestPackageParser2(),
ParallelPackageParser.makeExecutorService());
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 2cbb6d5..06b344b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -8595,6 +8595,56 @@
}
}
+ public void testIsSharingShortcut() throws IntentFilter.MalformedMimeTypeException {
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_share_targets);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+ setCaller(CALLING_PACKAGE_1, USER_0);
+
+ final ShortcutInfo s1 = makeShortcutWithCategory("s1",
+ set("com.test.category.CATEGORY1", "com.test.category.CATEGORY2"));
+ final ShortcutInfo s2 = makeShortcutWithCategory("s2",
+ set("com.test.category.CATEGORY5", "com.test.category.CATEGORY6"));
+ final ShortcutInfo s3 = makeShortcut("s3");
+
+ assertTrue(mManager.setDynamicShortcuts(list(s1, s2, s3)));
+ assertShortcutIds(assertAllNotKeyFieldsOnly(mManager.getDynamicShortcuts()),
+ "s1", "s2", "s3");
+
+ IntentFilter filter_cat1 = new IntentFilter();
+ filter_cat1.addDataType("text/plain");
+ IntentFilter filter_cat5 = new IntentFilter();
+ filter_cat5.addDataType("video/*");
+ IntentFilter filter_any = new IntentFilter();
+ filter_any.addDataType("*/*");
+
+ setCaller(LAUNCHER_1, USER_0);
+ mCallerPermissions.add(permission.MANAGE_APP_PREDICTIONS);
+
+ assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0,
+ filter_cat1));
+ assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0,
+ filter_cat5));
+ assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s1", USER_0,
+ filter_any));
+
+ assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_0,
+ filter_cat1));
+ assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_0,
+ filter_cat5));
+ assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s2", USER_0,
+ filter_any));
+
+ assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_0,
+ filter_any));
+ assertFalse(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s4", USER_0,
+ filter_any));
+ }
+
private Uri getFileUriFromResource(String fileName, int resId) throws IOException {
File file = new File(getTestContext().getFilesDir(), fileName);
// Make sure we are not leaving phantom files behind.
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index f87f68d..3888ff3 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -35,7 +35,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.servicestests.R;
-import com.android.server.pm.parsing.PackageParser2;
+import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
@@ -93,15 +93,11 @@
return outFile;
}
- private PackageParser2 makeParser() {
- return new PackageParser2(null, false, null, null, null);
- }
-
@Test
public void testParsePackageWithDmFileValid() throws IOException, PackageParserException {
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
createDexMetadataFile("install_split_base.apk");
- ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
+ ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, 0 /* flags */, false);
Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
assertEquals(1, packageDexMetadata.size());
@@ -117,7 +113,7 @@
copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
createDexMetadataFile("install_split_base.apk");
createDexMetadataFile("install_split_feature_a.apk");
- ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
+ ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, 0 /* flags */, false);
Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
assertEquals(2, packageDexMetadata.size());
@@ -136,7 +132,7 @@
copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base);
copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a);
createDexMetadataFile("install_split_feature_a.apk");
- ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
+ ParsedPackage pkg = new TestPackageParser2().parsePackage(mTmpDir, 0 /* flags */, false);
Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
assertEquals(1, packageDexMetadata.size());
@@ -152,7 +148,8 @@
File invalidDmFile = new File(mTmpDir, "install_split_base.dm");
Files.createFile(invalidDmFile.toPath());
try {
- ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
+ ParsedPackage pkg = new TestPackageParser2()
+ .parsePackage(mTmpDir, 0 /* flags */, false);
AndroidPackageUtils.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
@@ -169,7 +166,8 @@
Files.createFile(invalidDmFile.toPath());
try {
- ParsedPackage pkg = makeParser().parsePackage(mTmpDir, 0 /* flags */, false);
+ ParsedPackage pkg = new TestPackageParser2()
+ .parsePackage(mTmpDir, 0 /* flags */, false);
AndroidPackageUtils.validatePackageDexMetadata(pkg);
} catch (PackageParserException e) {
assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA);
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index ca6b296..19bf9b67 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -31,12 +31,12 @@
import android.os.Environment
import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.om.mockThrowOnUnmocked
-import com.android.server.om.whenever
import com.android.server.pm.PackageManagerService
import com.android.server.pm.PackageSetting
import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageStateUnserialized
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.whenever
import org.junit.BeforeClass
import org.mockito.Mockito
import org.mockito.Mockito.anyInt
@@ -47,8 +47,7 @@
companion object {
- // TODO(chiuwinson): Enable in separate change to fail all presubmit builds and fix errors
- private const val VERIFY_ALL_APKS = false
+ private const val VERIFY_ALL_APKS = true
/** For auditing memory usage differences */
private const val DUMP_HPROF_TO_EXTERNAL = false
@@ -57,13 +56,10 @@
protected val packageParser = PackageParser().apply {
setOnlyCoreApps(false)
setDisplayMetrics(context.resources.displayMetrics)
- setCallback { true }
+ setCallback { false /* hasFeature */ }
}
- protected val packageParser2 = PackageParser2(null, false, context.resources.displayMetrics,
- null, object : PackageParser2.Callback() {
- override fun hasFeature(feature: String?) = true
- })
+ protected val packageParser2 = TestPackageParser2()
/**
* It would be difficult to mock all possibilities, so just use the APKs on device.
@@ -95,24 +91,35 @@
lateinit var newPackages: List<AndroidPackage>
+ var failureInBeforeClass: Throwable? = null
+
@Suppress("ConstantConditionIf")
@JvmStatic
@BeforeClass
fun setUpPackages() {
- this.oldPackages = apks.map {
- packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
- }
+ failureInBeforeClass = null
+ try {
+ this.oldPackages = apks.map {
+ packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
+ }
- this.newPackages = apks.map {
- packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
- }
+ this.newPackages = apks.map {
+ packageParser2.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false)
+ }
- if (DUMP_HPROF_TO_EXTERNAL) {
- System.gc()
- Environment.getExternalStorageDirectory()
- .resolve("${AndroidPackageParsingTestBase::class.java.simpleName}.hprof")
- .absolutePath
- .run(Debug::dumpHprofData)
+ if (DUMP_HPROF_TO_EXTERNAL) {
+ System.gc()
+ Environment.getExternalStorageDirectory()
+ .resolve(
+ "${AndroidPackageParsingTestBase::class.java.simpleName}.hprof")
+ .absolutePath
+ .run(Debug::dumpHprofData)
+ }
+ } catch (t: Throwable) {
+ // If we crash here we cause a tool failure (because we don't run any of the tests
+ // in the subclasses, leading to a difference between expected and actual test
+ // result counts).
+ failureInBeforeClass = t
}
}
@@ -141,6 +148,13 @@
}
}
+ @org.junit.Before
+ fun verifySetUpPackages() {
+ failureInBeforeClass?.let {
+ throw AssertionError("setUpPackages failed:", it)
+ }
+ }
+
// The following methods dump an exact set of fields from the object to compare, because
// 1. comprehensive equals/toStrings do not exist on all of the Info objects, and
// 2. the test must only verify fields that [PackageParser.Package] can actually fill, as
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 66cd466..af89761 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -102,10 +102,6 @@
}
}
- private PackageParser2 makeParser() {
- return new PackageParser2(null, false, null, null, null);
- }
-
@Test
public void testComputeMinSdkVersion_preReleasePlatform() {
// Do allow older release minSdkVersion on pre-release platform.
@@ -357,8 +353,8 @@
File outFile = null;
try {
outFile = copyRawResourceToFile(apkFileName, apkResourceId);
- return converter.apply(
- makeParser().parsePackage(outFile, 0 /* flags */, false));
+ return converter.apply(new TestPackageParser2()
+ .parsePackage(outFile, 0 /* flags */, false));
} finally {
if (outFile != null) {
outFile.delete();
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
new file mode 100644
index 0000000..2248707
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.parsing
+
+import android.annotation.RawRes
+import android.content.Context
+import android.content.pm.parsing.ParsingPackage
+import android.content.pm.parsing.ParsingPackageImpl
+import android.content.pm.parsing.ParsingPackageUtils
+import android.content.pm.parsing.result.ParseInput
+import android.content.pm.parsing.result.ParseInput.DeferredError
+import android.content.pm.parsing.result.ParseResult
+import android.content.res.TypedArray
+import android.os.Build
+import androidx.test.InstrumentationRegistry
+import com.android.frameworks.servicestests.R
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+
+/**
+ * There are 2 known errors when parsing a manifest that were promoted to true failures in R:
+ * 1. Missing an <application> or <instrumentation> tag
+ * 2. An empty string action/category in an intent-filter
+ *
+ * This verifies these failures when the APK targets R.
+ */
+class PackageParsingDeferErrorTest {
+
+ companion object {
+ private const val TEST_ACTIVITY =
+ "com.android.servicestests.pm.parsing.test.TestActivity"
+ private const val TEST_ACTION =
+ "com.android.servicestests.pm.parsing.test.TEST_ACTION"
+ private const val TEST_CATEGORY =
+ "com.android.servicestests.pm.parsing.test.TEST_CATEGORY"
+ private const val TEST_PERMISSION =
+ "com.android.servicestests.pm.parsing.missingapp.TEST_PERMISSION"
+ }
+
+ private val context: Context = InstrumentationRegistry.getContext()
+
+ private val inputCallback = ParseInput.Callback { changeId, _, targetSdk ->
+ when (changeId) {
+ DeferredError.MISSING_APP_TAG -> targetSdk > Build.VERSION_CODES.Q
+ DeferredError.EMPTY_INTENT_ACTION_CATEGORY -> targetSdk > Build.VERSION_CODES.Q
+ else -> throw IllegalStateException("changeId $changeId is not mocked for test")
+ }
+ }
+
+ private val parsingCallback = object : ParsingPackageUtils.Callback {
+ override fun hasFeature(feature: String?) = true
+
+ override fun startParsingPackage(
+ packageName: String,
+ baseCodePath: String,
+ codePath: String,
+ manifestArray: TypedArray,
+ isCoreApp: Boolean
+ ): ParsingPackage {
+ return ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray)
+ }
+ }
+
+ @get:Rule
+ val tempFolder = TemporaryFolder(context.filesDir)
+
+ @Test
+ fun emptyIntentFilterActionSdkQ() {
+ val result = parseFile(R.raw.PackageParsingTestAppEmptyActionSdkQ)
+ assertWithMessage(result.errorMessage).that(result.isError).isFalse()
+ val activities = result.result.activities
+ // 2 because of AppDetailsActivity
+ assertThat(activities).hasSize(2)
+ val first = activities.first()
+ assertThat(first.name).isEqualTo(TEST_ACTIVITY)
+ val intents = first.intents
+ assertThat(intents).hasSize(1)
+ assertThat(intents.first().hasCategory(TEST_CATEGORY)).isTrue()
+ assertThat(intents.first().hasAction(TEST_ACTION)).isTrue()
+ }
+
+ @Test
+ fun emptyIntentFilterActionSdkR() {
+ val result = parseFile(R.raw.PackageParsingTestAppEmptyActionSdkR)
+ assertThat(result.isError).isTrue()
+ }
+
+ @Test
+ fun emptyIntentFilterCategorySdkQ() {
+ val result = parseFile(R.raw.PackageParsingTestAppEmptyCategorySdkQ)
+ assertWithMessage(result.errorMessage).that(result.isError).isFalse()
+ val activities = result.result.activities
+ // 2 because of AppDetailsActivity
+ assertThat(activities).hasSize(2)
+ val first = activities.first()
+ assertThat(first.name).isEqualTo(TEST_ACTIVITY)
+ val intents = first.intents
+ assertThat(intents).hasSize(1)
+ assertThat(intents.first().hasAction(TEST_ACTION)).isTrue()
+ }
+
+ @Test
+ fun emptyIntentFilterCategorySdkR() {
+ val result = parseFile(R.raw.PackageParsingTestAppEmptyCategorySdkR)
+ assertThat(result.isError).isTrue()
+ }
+
+ @Test
+ fun missingAppTagSdkQ() {
+ val result = parseFile(R.raw.PackageParsingTestAppMissingAppSdkQ)
+ assertWithMessage(result.errorMessage).that(result.isError).isFalse()
+ val permissions = result.result.permissions
+ assertThat(permissions).hasSize(1)
+ assertThat(permissions.first().name).isEqualTo(TEST_PERMISSION)
+ }
+
+ @Test
+ fun missingAppTagSdkR() {
+ val result = parseFile(R.raw.PackageParsingTestAppMissingAppSdkR)
+ assertThat(result.isError).isTrue()
+ }
+
+ private fun parseFile(@RawRes id: Int): ParseResult<ParsingPackage> {
+ val file = tempFolder.newFile()
+ context.resources.openRawResource(id).use { input ->
+ file.outputStream().use { output ->
+ input.copyTo(output)
+ }
+ }
+ return ParsingPackageUtils.parseDefaultOneTime(file, 0, inputCallback, parsingCallback)
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
new file mode 100644
index 0000000..7ca7682
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.parsing
+
+import android.content.pm.ApplicationInfo
+
+class TestPackageParser2 : PackageParser2(null /* separateProcesses */, false /* onlyCoreApps */,
+ null /* displayMetrics */, null /* cacheDir */, object : PackageParser2.Callback() {
+ override fun isChangeEnabled(changeId: Long, appInfo: ApplicationInfo): Boolean {
+ return true
+ }
+
+ override fun hasFeature(feature: String): Boolean {
+ // Assume the device doesn't support anything. This will affect permission parsing
+ // and will force <uses-permission/> declarations to include all requiredNotFeature
+ // permissions and exclude all requiredFeature permissions. This mirrors the old
+ // behavior.
+ return false
+ }
+})
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 06b5fe4..ebcf10d 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -1106,7 +1106,7 @@
public void testAbortRecognition() throws Exception {
// Make sure the HAL doesn't support concurrent capture.
initService(false);
- mService.setExternalCaptureState(false);
+ mService.setCaptureState(false);
ISoundTriggerCallback callback = createCallbackMock();
ISoundTriggerModule module = mService.attach(0, callback);
@@ -1120,7 +1120,7 @@
startRecognition(module, handle, hwHandle);
// Abort.
- mService.setExternalCaptureState(true);
+ mService.setCaptureState(true);
ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
RecognitionEvent.class);
@@ -1142,7 +1142,7 @@
verifyNotStartRecognition();
// Now enable it and make sure we are notified.
- mService.setExternalCaptureState(false);
+ mService.setCaptureState(false);
verify(callback).onRecognitionAvailabilityChange(true);
// Unload the model.
@@ -1154,7 +1154,7 @@
public void testAbortPhraseRecognition() throws Exception {
// Make sure the HAL doesn't support concurrent capture.
initService(false);
- mService.setExternalCaptureState(false);
+ mService.setCaptureState(false);
ISoundTriggerCallback callback = createCallbackMock();
ISoundTriggerModule module = mService.attach(0, callback);
@@ -1168,7 +1168,7 @@
startRecognition(module, handle, hwHandle);
// Abort.
- mService.setExternalCaptureState(true);
+ mService.setCaptureState(true);
ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
PhraseRecognitionEvent.class);
@@ -1190,7 +1190,7 @@
verifyNotStartRecognition();
// Now enable it and make sure we are notified.
- mService.setExternalCaptureState(false);
+ mService.setCaptureState(false);
verify(callback).onRecognitionAvailabilityChange(true);
// Unload the model.
@@ -1216,7 +1216,7 @@
startRecognition(module, handle, hwHandle);
// Signal concurrent capture. Shouldn't abort.
- mService.setExternalCaptureState(true);
+ mService.setCaptureState(true);
verify(callback, never()).onRecognition(anyInt(), any());
verify(callback, never()).onRecognitionAvailabilityChange(anyBoolean());
@@ -1252,7 +1252,7 @@
startRecognition(module, handle, hwHandle);
// Signal concurrent capture. Shouldn't abort.
- mService.setExternalCaptureState(true);
+ mService.setCaptureState(true);
verify(callback, never()).onPhraseRecognition(anyInt(), any());
verify(callback, never()).onRecognitionAvailabilityChange(anyBoolean());
diff --git a/services/tests/servicestests/test-apps/PackageParsingTestManifests/Android.bp b/services/tests/servicestests/test-apps/PackageParsingTestManifests/Android.bp
new file mode 100644
index 0000000..8eb56f6
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParsingTestManifests/Android.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2019 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.
+
+// NOTE: NONE_OF_THESE_TARGETS_ACTUALLY_WORK. AAPT2 doesn't seem to be able to skip
+// errors within tag attributes. This is here as an reference of how to build the test apps, but
+// they will have to built manually and checked into the tree as prebuilts. A modified version of
+// AAPT2 is necessary to build the broken APKs.
+
+// android_test_helper_app {
+// name: "PackageParsingTestAppEmptyActionSdkQ",
+// manifest: "AndroidManifestEmptyAction.xml",
+// srcs: ["**/*.kt"],
+// min_sdk_version: "28",
+// target_sdk_version: "29",
+// aaptflags: ["--warn-manifest-validation"],
+// }
+
+// android_test_helper_app {
+// name: "PackageParsingTestAppEmptyActionSdkR",
+// manifest: "AndroidManifestEmptyAction.xml",
+// srcs: ["**/*.kt"],
+// min_sdk_version: "28",
+// target_sdk_version: "30",
+// aaptflags: ["--warn-manifest-validation"],
+// }
+
+// android_test_helper_app {
+// name: "PackageParsingTestAppEmptyCategorySdkQ",
+// manifest: "AndroidManifestEmptyCategory.xml",
+// srcs: ["**/*.kt"],
+// min_sdk_version: "28",
+// target_sdk_version: "29",
+// aaptflags: ["--warn-manifest-validation"],
+// }
+
+// android_test_helper_app {
+// name: "PackageParsingTestAppEmptyCategorySdkR",
+// manifest: "AndroidManifestEmptyCategory.xml",
+// srcs: ["**/*.kt"],
+// min_sdk_version: "28",
+// target_sdk_version: "30",
+// aaptflags: ["--warn-manifest-validation"],
+// }
+
+// android_test_helper_app {
+// name: "PackageParsingTestAppMissingAppSdkQ",
+// manifest: "AndroidManifestMissingApp.xml",
+// min_sdk_version: "28",
+// target_sdk_version: "29",
+// aaptflags: ["--warn-manifest-validation"],
+// }
+
+// android_test_helper_app {
+// name: "PackageParsingTestAppMissingAppSdkR",
+// manifest: "AndroidManifestMissingApp.xml",
+// min_sdk_version: "28",
+// target_sdk_version: "30",
+// aaptflags: ["--warn-manifest-validation"],
+// }
diff --git a/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestEmptyAction.xml b/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestEmptyAction.xml
new file mode 100644
index 0000000..cb294f6
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestEmptyAction.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.servicestests.pm.parsing.emptyaction">
+
+ <application>
+ <activity android:name="com.android.servicestests.pm.parsing.test.TestActivity">
+ <intent-filter>
+ <action android:name="" />
+ <!-- Non-empty action use to verify filter, since 0 action filters are stripped -->
+ <action android:name="com.android.servicestests.pm.parsing.test.TEST_ACTION" />
+ <category android:name="com.android.servicestests.pm.parsing.test.TEST_CATEGORY"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestEmptyCategory.xml b/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestEmptyCategory.xml
new file mode 100644
index 0000000..5b0f80a
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestEmptyCategory.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.servicestests.pm.parsing.emptycategory">
+
+ <application>
+ <activity android:name="com.android.servicestests.pm.parsing.test.TestActivity">
+ <intent-filter>
+ <action android:name="com.android.servicestests.pm.parsing.test.TEST_ACTION"/>
+ <category android:name="" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestMissingApp.xml b/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestMissingApp.xml
new file mode 100644
index 0000000..3824947
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParsingTestManifests/AndroidManifestMissingApp.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.servicestests.pm.parsing.missingapp">
+
+ <!-- Only to assert that the manifest parsed correctly -->
+ <permission android:name="com.android.servicestests.pm.parsing.missingapp.TEST_PERMISSION"
+ android:protectionLevel="normal" />
+
+</manifest>
diff --git a/services/tests/servicestests/test-apps/PackageParsingTestManifests/src/com/android/servicestests/pm/parsing/test/TestActivity.kt b/services/tests/servicestests/test-apps/PackageParsingTestManifests/src/com/android/servicestests/pm/parsing/test/TestActivity.kt
new file mode 100644
index 0000000..3b8b29d
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParsingTestManifests/src/com/android/servicestests/pm/parsing/test/TestActivity.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 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.servicestests.pm.parsing.test
+
+class TestActivity
diff --git a/services/tests/servicestests/src/com/android/server/om/MockitoUtils.kt b/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
similarity index 74%
rename from services/tests/servicestests/src/com/android/server/om/MockitoUtils.kt
rename to services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
index 0f915db..056fa88 100644
--- a/services/tests/servicestests/src/com/android/server/om/MockitoUtils.kt
+++ b/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.om
+package com.android.server.testutils
import org.mockito.Answers
import org.mockito.Mockito
@@ -31,6 +31,13 @@
else -> {
val arguments = it.arguments
?.takeUnless { it.isEmpty() }
+ ?.mapIndexed { index, arg ->
+ try {
+ arg?.toString()
+ } catch (e: Exception) {
+ "toString[$index] threw ${e.message}"
+ }
+ }
?.joinToString()
?.let {
"with $it"
@@ -46,6 +53,8 @@
inline fun <reified T> mock(block: T.() -> Unit = {}) = Mockito.mock(T::class.java).apply(block)
+fun <T> spy(value: T, block: T.() -> Unit = {}) = Mockito.spy(value).apply(block)
+
fun <Type> Stubber.whenever(mock: Type) = Mockito.`when`(mock)
fun <Type : Any?> whenever(mock: Type) = Mockito.`when`(mock)
@@ -55,7 +64,7 @@
fun whenever(mock: Unit) = Mockito.`when`(mock).thenAnswer { }
-inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit): T {
+inline fun <reified T> spyThrowOnUnmocked(value: T?, block: T.() -> Unit): T {
val swappingAnswer = object : Answer<Any?> {
var delegate: Answer<*> = Answers.RETURNS_DEFAULTS
@@ -64,9 +73,12 @@
}
}
- return Mockito.mock(T::class.java, swappingAnswer).apply(block)
+ return Mockito.mock(T::class.java, Mockito.withSettings().spiedInstance(value)
+ .defaultAnswer(swappingAnswer)).apply(block)
.also {
// To allow when() usage inside block, only swap to throwing afterwards
swappingAnswer.delegate = MockitoUtils.ANSWER_THROWS
}
}
+
+inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit) = spyThrowOnUnmocked<T>(null, block)
diff --git a/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
index 69db384..355e7f3 100644
--- a/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
@@ -139,7 +139,7 @@
}
}
- private class MsgInfo implements Comparable<MsgInfo> {
+ public class MsgInfo implements Comparable<MsgInfo> {
public final Message message;
public final long sendTime;
public final RuntimeException postPoint;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 319e9ac..1d952bf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -83,7 +83,7 @@
import android.service.voice.IVoiceInteractionSession;
import android.view.Gravity;
import android.window.ITaskOrganizer;
-import android.window.IWindowContainer;
+import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
@@ -1014,10 +1014,10 @@
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
mService.mTaskOrganizerController.registerTaskOrganizer(this,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- IWindowContainer primary = mService.mTaskOrganizerController.createRootTask(
+ WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
- IWindowContainer secondary = mService.mTaskOrganizerController.createRootTask(
+ WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask(
displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
}
@@ -1037,7 +1037,7 @@
== WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
mInSplit = true;
mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
- mSecondary.mRemoteToken);
+ mSecondary.mRemoteToken.toWindowContainerToken());
// move everything to secondary because test expects this but usually sysui
// does it.
DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 08e492a..8b91c7e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -73,7 +73,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testKeyguardOverride() {
mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
@@ -81,7 +80,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testKeyguardKeep() {
mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
@@ -89,7 +87,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testForceOverride() {
mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
mDc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
@@ -105,7 +102,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testKeepKeyguard_withCrashing() {
mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
@@ -113,7 +109,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testAppTransitionStateForMultiDisplay() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
@@ -182,7 +177,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testLoadAnimationSafely() {
DisplayContent dc = createNewDisplay(Display.STATE_ON);
assertNull(dc.mAppTransition.loadAnimationSafely(
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index 6e78a27..b93a8fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -67,7 +67,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void clipAfterAnim_boundsLayerIsCreated() {
mActivity.mNeedsAnimationBoundsLayer = true;
@@ -91,7 +90,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void clipAfterAnim_boundsLayerIsDestroyed() {
mActivity.mNeedsAnimationBoundsLayer = true;
mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
@@ -126,7 +124,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void clipNoneAnim_boundsLayerIsNotCreated() {
mActivity.mNeedsAnimationBoundsLayer = false;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 7928e76..28ae36a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -677,7 +677,6 @@
}
@Test
- @FlakyTest(bugId = 149760800)
public void layoutWindowLw_withLongEdgeDisplayCutout() {
addLongEdgeDisplayCutout();
@@ -698,7 +697,6 @@
}
@Test
- @FlakyTest(bugId = 149760800)
public void layoutWindowLw_withLongEdgeDisplayCutout_never() {
addLongEdgeDisplayCutout();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index c370d6c..d0fd50d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -277,7 +277,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testOverlappingWithNavBar() {
final WindowState targetWin = createApplicationWindow();
final WindowFrames winFrame = targetWin.getWindowFrames();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 956c200..0eee3ca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -147,19 +147,16 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testDragFlow() {
dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
}
@Test
- @FlakyTest(bugId = 131005232)
public void testPerformDrag_NullDataWithGrantUri() {
dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
}
@Test
- @FlakyTest(bugId = 131005232)
public void testPerformDrag_NullDataToOtherUser() {
final WindowState otherUsersWindow =
createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index b21ea79..89bc65b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -58,7 +58,6 @@
import org.junit.runner.RunWith;
@SmallTest
-@FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Presubmit
@RunWith(WindowTestRunner.class)
public class InsetsPolicyTest extends WindowTestsBase {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index db7bce4..61b74b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -32,6 +32,10 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
@@ -49,7 +53,6 @@
import org.junit.runner.RunWith;
@SmallTest
-@FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Presubmit
@RunWith(WindowTestRunner.class)
public class InsetsStateControllerTest extends WindowTestsBase {
@@ -68,7 +71,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testStripForDispatch_notOwn() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
@@ -102,7 +104,8 @@
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
- assertEquals(0, getController().getInsetsForDispatch(navBar).getSourcesCount());
+ assertNull(getController().getInsetsForDispatch(navBar).peekSource(ITYPE_IME));
+ assertNull(getController().getInsetsForDispatch(navBar).peekSource(ITYPE_STATUS_BAR));
}
@Test
@@ -169,6 +172,45 @@
}
@Test
+ public void testStripForDispatch_imeOrderChanged() {
+ getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
+
+ // This window can be the IME target while app cannot be the IME target.
+ createWindow(null, TYPE_APPLICATION, "base");
+
+ // Send our spy window (app) into the system so that we can detect the invocation.
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "app");
+ final WindowToken parent = win.mToken;
+ parent.removeChild(win);
+ final WindowState app = spy(win);
+ parent.addWindow(app);
+
+ // Adding FLAG_NOT_FOCUSABLE makes app above IME.
+ app.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+ mDisplayContent.computeImeTarget(true);
+ mDisplayContent.setLayoutNeeded();
+ mDisplayContent.applySurfaceChangesTransaction();
+
+ // app won't get IME insets while above IME.
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
+
+ // Reset invocation counter.
+ clearInvocations(app);
+
+ // Removing FLAG_NOT_FOCUSABLE makes app below IME.
+ app.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
+ mDisplayContent.computeImeTarget(true);
+ mDisplayContent.setLayoutNeeded();
+ mDisplayContent.applySurfaceChangesTransaction();
+
+ // Make sure app got notified.
+ verify(app, atLeast(1)).notifyInsetsChanged();
+
+ // app will get IME insets while below IME.
+ assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
+ }
+
+ @Test
public void testStripForDispatch_childWindow_altFocusable() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
@@ -247,7 +289,6 @@
assertNull(getController().getControlsForDispatch(app));
}
- @FlakyTest(bugId = 124088319)
@Test
public void testControlRevoked_animation() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 34ac835..67aab7e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -146,7 +146,6 @@
}
@Test
- @FlakyTest(bugId = 133372977)
public void testTimeout() throws Exception {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index f05acce..6ef714e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -26,6 +26,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -282,7 +284,7 @@
final Task task = stack.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
Rect newBounds = new Rect(10, 10, 100, 100);
- t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
+ t.setBounds(task.mRemoteToken.toWindowContainerToken(), new Rect(10, 10, 100, 100));
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertEquals(newBounds, task.getBounds());
}
@@ -295,7 +297,7 @@
StackInfo info =
mWm.mAtmService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
WindowContainerTransaction t = new WindowContainerTransaction();
- assertEquals(stack.mRemoteToken, info.stackToken);
+ assertEquals(stack.mRemoteToken.toWindowContainerToken(), info.stackToken);
Rect newBounds = new Rect(10, 10, 100, 100);
t.setBounds(info.stackToken, new Rect(10, 10, 100, 100));
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
@@ -308,7 +310,7 @@
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
final WindowContainerTransaction t = new WindowContainerTransaction();
- t.setWindowingMode(stack.mRemoteToken, WINDOWING_MODE_FULLSCREEN);
+ t.setWindowingMode(stack.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_FULLSCREEN);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertEquals(WINDOWING_MODE_FULLSCREEN, stack.getWindowingMode());
@@ -320,8 +322,9 @@
final ActivityStack stack = record.getStack();
final WindowContainerTransaction t = new WindowContainerTransaction();
- t.setWindowingMode(stack.mRemoteToken, WINDOWING_MODE_PINNED);
- t.setActivityWindowingMode(stack.mRemoteToken, WINDOWING_MODE_FULLSCREEN);
+ t.setWindowingMode(stack.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_PINNED);
+ t.setActivityWindowingMode(
+ stack.mRemoteToken.toWindowContainerToken(), WINDOWING_MODE_FULLSCREEN);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertEquals(WINDOWING_MODE_FULLSCREEN, record.getWindowingMode());
@@ -336,10 +339,10 @@
final Task task = stack.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
assertTrue(task.isFocusable());
- t.setFocusable(stack.mRemoteToken, false);
+ t.setFocusable(stack.mRemoteToken.toWindowContainerToken(), false);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertFalse(task.isFocusable());
- t.setFocusable(stack.mRemoteToken, true);
+ t.setFocusable(stack.mRemoteToken.toWindowContainerToken(), true);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertTrue(task.isFocusable());
}
@@ -351,10 +354,10 @@
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
WindowContainerTransaction t = new WindowContainerTransaction();
assertTrue(stack.shouldBeVisible(null));
- t.setHidden(stack.mRemoteToken, true);
+ t.setHidden(stack.mRemoteToken.toWindowContainerToken(), true);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertFalse(stack.shouldBeVisible(null));
- t.setHidden(stack.mRemoteToken, false);
+ t.setHidden(stack.mRemoteToken.toWindowContainerToken(), false);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertTrue(stack.shouldBeVisible(null));
}
@@ -366,19 +369,19 @@
.setWindowingMode(WINDOWING_MODE_FREEFORM).build();
final Task task = stack.getTopMostTask();
WindowContainerTransaction t = new WindowContainerTransaction();
- t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
+ t.setBounds(task.mRemoteToken.toWindowContainerToken(), new Rect(10, 10, 100, 100));
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
final int origScreenWDp = task.getConfiguration().screenHeightDp;
final int origScreenHDp = task.getConfiguration().screenHeightDp;
t = new WindowContainerTransaction();
// verify that setting config overrides on parent restricts children.
- t.setScreenSizeDp(stack.mRemoteToken, origScreenWDp, origScreenHDp);
- t.setBounds(task.mRemoteToken, new Rect(10, 10, 150, 200));
+ t.setScreenSizeDp(stack.mRemoteToken.toWindowContainerToken(), origScreenWDp, origScreenHDp);
+ t.setBounds(task.mRemoteToken.toWindowContainerToken(), new Rect(10, 10, 150, 200));
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
t = new WindowContainerTransaction();
- t.setScreenSizeDp(stack.mRemoteToken, Configuration.SCREEN_WIDTH_DP_UNDEFINED,
- Configuration.SCREEN_HEIGHT_DP_UNDEFINED);
+ t.setScreenSizeDp(stack.mRemoteToken.toWindowContainerToken(), SCREEN_WIDTH_DP_UNDEFINED,
+ SCREEN_HEIGHT_DP_UNDEFINED);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
assertNotEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
}
@@ -435,7 +438,7 @@
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken, info1.token, true /* onTop */);
+ wct.reparent(stack.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertEquals(info1.configuration.windowConfiguration.getWindowingMode(),
stack.getWindowingMode());
@@ -455,7 +458,7 @@
assertEquals(newSize, stack.getBounds());
wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken, null, true /* onTop */);
+ wct.reparent(stack.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
infos = getTasksCreatedByOrganizer(mDisplayContent);
@@ -495,7 +498,7 @@
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask();
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken, info1.token, true /* onTop */);
+ wct.reparent(stack.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertTrue(called[0]);
assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
@@ -505,7 +508,7 @@
final ActivityStack stack2 = createTaskStackOnDisplay(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent);
wct = new WindowContainerTransaction();
- wct.reparent(stack2.mRemoteToken, info1.token, true /* onTop */);
+ wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertTrue(called[0]);
assertEquals(ACTIVITY_TYPE_HOME, lastReportedTiles.get(0).topActivityType);
@@ -519,8 +522,8 @@
lastReportedTiles.clear();
called[0] = false;
wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken, null, true /* onTop */);
- wct.reparent(stack2.mRemoteToken, null, true /* onTop */);
+ wct.reparent(stack.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
+ wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), null, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertTrue(called[0]);
assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType);
@@ -569,8 +572,8 @@
lastReportedTiles.clear();
WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reparent(stack.mRemoteToken, info1.token, true /* onTop */);
- wct.reparent(stack2.mRemoteToken, info2.token, true /* onTop */);
+ wct.reparent(stack.mRemoteToken.toWindowContainerToken(), info1.token, true /* onTop */);
+ wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), info2.token, true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertFalse(lastReportedTiles.isEmpty());
assertEquals(ACTIVITY_TYPE_STANDARD,
@@ -580,7 +583,7 @@
lastReportedTiles.clear();
wct = new WindowContainerTransaction();
- wct.reparent(stack2.mRemoteToken, info1.token, false /* onTop */);
+ wct.reparent(stack2.mRemoteToken.toWindowContainerToken(), info1.token, false /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
assertFalse(lastReportedTiles.isEmpty());
// Standard should still be on top of tile 1, so no change there
@@ -605,7 +608,7 @@
lastReportedTiles.clear();
wct = new WindowContainerTransaction();
- wct.reorder(stack2.mRemoteToken, true /* onTop */);
+ wct.reorder(stack2.mRemoteToken.toWindowContainerToken(), true /* onTop */);
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
// Home should now be on top. No change occurs in second tile, so not reported
assertEquals(1, lastReportedTiles.size());
@@ -641,7 +644,7 @@
bse.setReady(id);
// Since this task has no windows the sync is trivial and completes immediately.
verify(transactionListener)
- .transactionReady(anyInt(), any());
+ .onTransactionReady(anyInt(), any());
}
@Test
@@ -691,10 +694,10 @@
bse.setReady(id);
// Since we have a window we have to wait for it to draw to finish sync.
verify(transactionListener, never())
- .transactionReady(anyInt(), any());
+ .onTransactionReady(anyInt(), any());
w.finishDrawing(null);
verify(transactionListener)
- .transactionReady(anyInt(), any());
+ .onTransactionReady(anyInt(), any());
}
@Test
@@ -716,7 +719,7 @@
// Since the window was invisible, the Task had no visible leaves and the sync should
// complete as soon as we call setReady.
verify(transactionListener)
- .transactionReady(anyInt(), any());
+ .onTransactionReady(anyInt(), any());
}
@Test
@@ -742,13 +745,13 @@
// Since we have a child window we still shouldn't be done.
verify(transactionListener, never())
- .transactionReady(anyInt(), any());
+ .onTransactionReady(anyInt(), any());
reset(transactionListener);
child.finishDrawing(null);
// Ah finally! Done
verify(transactionListener)
- .transactionReady(anyInt(), any());
+ .onTransactionReady(anyInt(), any());
}
class StubOrganizer extends ITaskOrganizer.Stub {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
index 9fc1602..12ed3c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
@@ -74,7 +74,6 @@
}
@Test
- @FlakyTest(bugId = 131005232)
public void testTaskIdsPersistence() {
SparseBooleanArray taskIdsOnFile = new SparseBooleanArray();
for (int i = 0; i < 100; i++) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index ea52d7d..93dcc91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -518,7 +518,6 @@
assertEquals(expected, actual);
}
- @FlakyTest(bugId = 129492888)
@Test
public void testFinishingMovingWhenBinderDied() {
spyOn(mWm.mTaskPositioningController);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index ca84932..75226b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -90,7 +90,6 @@
assertNull(mTarget.getDragWindowHandleLocked());
}
- @FlakyTest(bugId = 129507487)
@Test
public void testFinishPositioningWhenAppRequested() {
assertFalse(mTarget.isPositioningLocked());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 31d68a4..f76809b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -184,7 +184,6 @@
/** Ensures that bounds on freeform stacks are not clipped. */
@Test
- @FlakyTest(bugId = 137879065)
public void testAppBounds_FreeFormBounds() {
final Rect freeFormBounds = new Rect(mParentBounds);
freeFormBounds.offset(10, 10);
@@ -194,7 +193,6 @@
/** Ensures that fully contained bounds are not clipped. */
@Test
- @FlakyTest(bugId = 137879065)
public void testAppBounds_ContainedBounds() {
final Rect insetBounds = new Rect(mParentBounds);
insetBounds.inset(5, 5, 5, 5);
@@ -203,7 +201,6 @@
}
@Test
- @FlakyTest(bugId = 137879065)
public void testFitWithinBounds() {
final Rect parentBounds = new Rect(10, 10, 200, 200);
DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
@@ -243,7 +240,6 @@
/** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
@Test
- @FlakyTest(bugId = 137879065)
public void testBoundsOnModeChangeFreeformToFullscreen() {
DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
ActivityStack stack = new StackBuilder(mRootWindowContainer).setDisplay(display)
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e95ccab..820d381 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -449,7 +449,6 @@
}
@Test
- @FlakyTest(bugId = 74078662)
public void testLayoutSeqResetOnReparent() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
app.mLayoutSeq = 1;
@@ -508,7 +507,6 @@
}
@Test
- @FlakyTest(bugId = 74078662)
public void testDisplayCutoutIsCalculatedRelativeToFrame() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
WindowFrames wf = app.getWindowFrames();
diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
index 47bf148..6b19455 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
@@ -103,8 +103,7 @@
@Override
public void onIntentStarted(@NonNull Intent intent, long timestampNs) {
if (state == State.UNKNOWN) {
- logWarningWithStackTrace(
- String.format("IntentStarted during UNKNOWN. " + intent));
+ logWarningWithStackTrace("IntentStarted during UNKNOWN. " + intent);
incAccIntentStartedEvents();
return;
}
@@ -128,7 +127,7 @@
@Override
public void onIntentFailed() {
if (state == State.UNKNOWN) {
- logWarningWithStackTrace(String.format("onIntentFailed during UNKNOWN."));
+ logWarningWithStackTrace("onIntentFailed during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
@@ -147,8 +146,7 @@
public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
@Temperature int temperature) {
if (state == State.UNKNOWN) {
- logWarningWithStackTrace(
- String.format("onActivityLaunched during UNKNOWN."));
+ logWarningWithStackTrace("onActivityLaunched during UNKNOWN.");
return;
}
if (state != State.INTENT_STARTED) {
@@ -165,8 +163,7 @@
@Override
public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
if (state == State.UNKNOWN) {
- logWarningWithStackTrace(
- String.format("onActivityLaunchCancelled during UNKNOWN."));
+ logWarningWithStackTrace("onActivityLaunchCancelled during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
@@ -185,8 +182,7 @@
public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity,
long timestampNs) {
if (state == State.UNKNOWN) {
- logWarningWithStackTrace(
- String.format("onActivityLaunchFinished during UNKNOWN."));
+ logWarningWithStackTrace("onActivityLaunchFinished during UNKNOWN.");
decAccIntentStartedEvents();
return;
}
@@ -206,8 +202,7 @@
public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
long timestampNs) {
if (state == State.UNKNOWN) {
- logWarningWithStackTrace(
- String.format("onReportFullyDrawn during UNKNOWN."));
+ logWarningWithStackTrace("onReportFullyDrawn during UNKNOWN.");
return;
}
if (state == State.INIT) {
@@ -237,8 +232,7 @@
private void incAccIntentStartedEvents() {
if (accIntentStartedEvents < 0) {
- throw new AssertionError(
- String.format("The number of unknowns cannot be negative"));
+ throw new AssertionError("The number of unknowns cannot be negative");
}
if (accIntentStartedEvents == 0) {
state = State.UNKNOWN;
@@ -250,8 +244,7 @@
private void decAccIntentStartedEvents() {
if (accIntentStartedEvents <= 0) {
- throw new AssertionError(
- String.format("The number of unknowns cannot be negative"));
+ throw new AssertionError("The number of unknowns cannot be negative");
}
if(accIntentStartedEvents == 1) {
state = State.INIT;
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 6fdc13e..d524299 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -493,6 +493,7 @@
int RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT = 209;
int RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS = 210;
int RIL_REQUEST_GET_BARRING_INFO = 211;
+ int RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION = 212;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index 342c47d..7d918cc 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -17,7 +17,10 @@
android_test {
name: "PlatformCompatGating",
// Only compile source java files in this apk.
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
test_suites: ["device-tests"],
static_libs: [
"junit",
@@ -25,7 +28,8 @@
"androidx.test.core",
"androidx.test.ext.junit",
"mockito-target-minus-junit4",
+ "testng",
"truth-prebuilt",
- "platform-compat-test-rules"
+ "platform-compat-test-rules",
],
}
diff --git a/tests/PlatformCompatGating/AndroidManifest.xml b/tests/PlatformCompatGating/AndroidManifest.xml
index c24dc31..0510db2 100644
--- a/tests/PlatformCompatGating/AndroidManifest.xml
+++ b/tests/PlatformCompatGating/AndroidManifest.xml
@@ -2,6 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.tests.gating">
+
+ <queries>
+ <package android:name="com.android.tests.gating.app_not_installed" />
+ </queries>
+
<application android:label="GatingTest">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
new file mode 100644
index 0000000..0f62c4f
--- /dev/null
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 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.tests.gating
+
+import android.Manifest
+import android.app.UiAutomation
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.parsing.result.ParseInput
+import android.os.Build
+import android.os.ParcelFileDescriptor
+import android.os.ServiceManager
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.internal.compat.IPlatformCompat
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.testng.Assert.assertThrows
+import java.io.FileReader
+
+/**
+ * Verifies the shell commands "am compat enable/disable/reset" against a real server change ID
+ * for a not installed package.
+ *
+ * This class intentionally does not use any PlatformCompat testing infrastructure since that could
+ * interfere with what it's testing.
+ */
+@RunWith(Parameterized::class)
+class PlatformCompatCommandNotInstalledTest {
+
+ companion object {
+
+ private const val TEST_PKG = "com.android.tests.gating.app_not_installed"
+ private const val TEST_CHANGE_ID = ParseInput.DeferredError.MISSING_APP_TAG
+
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ @JvmStatic
+ @BeforeClass
+ fun assumeDebuggable() {
+ assumeTrue(Build.IS_DEBUGGABLE)
+ }
+
+ @JvmStatic
+ @BeforeClass
+ fun assertNotInstalled() {
+ assertThrows(PackageManager.NameNotFoundException::class.java) {
+ instrumentation.context.packageManager
+ .getApplicationInfo(TEST_PKG, PackageManager.MATCH_ALL)
+ }
+ }
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters() = arrayOf(
+ Params(enableDisable = null, targetSdk = 29, result = false),
+ Params(enableDisable = null, targetSdk = 30, result = true),
+
+ Params(enableDisable = true, targetSdk = 29, result = true),
+ Params(enableDisable = true, targetSdk = 30, result = true),
+
+ Params(enableDisable = false, targetSdk = 29, result = false),
+ Params(enableDisable = false, targetSdk = 30, result = false)
+ )
+ }
+
+ data class Params(val enableDisable: Boolean?, val targetSdk: Int, val result: Boolean)
+
+ @Parameterized.Parameter(0)
+ lateinit var params: Params
+
+ private val uiAutomation: UiAutomation = instrumentation.getUiAutomation()
+ private val platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE))
+
+ @Before
+ fun resetChangeId() {
+ uiAutomation.adoptShellPermissionIdentity(Manifest.permission.LOG_COMPAT_CHANGE,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG)
+
+ val result = command("am compat reset $TEST_CHANGE_ID $TEST_PKG")
+ assertThat(result.startsWith("Reset change") || result.startsWith("No override"))
+ .isTrue()
+ }
+
+ fun ParcelFileDescriptor.text() = FileReader(fileDescriptor).readText()
+
+ @After
+ fun resetIdentity() = uiAutomation.dropShellPermissionIdentity()
+
+ @Test
+ fun execute() {
+ when (params.enableDisable) {
+ null -> { /* do nothing */
+ }
+ true -> assertThat(command("am compat enable $TEST_CHANGE_ID $TEST_PKG"))
+ .startsWith("Enabled change")
+ false -> assertThat(command("am compat disable $TEST_CHANGE_ID $TEST_PKG"))
+ .startsWith("Disabled change")
+ }
+
+ val appInfo = ApplicationInfo().apply {
+ this.packageName = TEST_PKG
+ this.targetSdkVersion = params.targetSdk
+ }
+
+ assertThat(platformCompat.isChangeEnabled(TEST_CHANGE_ID, appInfo)).isEqualTo(params.result)
+ }
+
+ private fun command(command: String) =
+ FileReader(uiAutomation.executeShellCommand(command).fileDescriptor).readText()
+}
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 24623fb..2be4ae6 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -39,7 +39,7 @@
name: "NetworkStagedRollbackTest",
srcs: ["NetworkStagedRollbackTest/src/**/*.java"],
libs: ["tradefed"],
- static_libs: ["testng", "RollbackTestLib"],
+ static_libs: ["RollbackTestLib"],
test_suites: ["general-tests"],
test_config: "NetworkStagedRollbackTest.xml",
}
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
index f6dcff4..57c52f9 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
@@ -20,7 +20,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import static org.testng.Assert.assertThrows;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -31,6 +30,7 @@
import org.junit.runner.RunWith;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/**
* Runs the network rollback tests.
@@ -83,11 +83,12 @@
// Verify rollback was enabled
runPhase("testNetworkFailedRollback_Phase2");
- assertThrows(AssertionError.class, () -> runPhase("testNetworkFailedRollback_Phase3"));
-
+ // Wait for reboot to happen
+ assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(5)));
+ // Wait for reboot to complete and device to become available
getDevice().waitForDeviceAvailable();
// Verify rollback was executed after health check deadline
- runPhase("testNetworkFailedRollback_Phase4");
+ runPhase("testNetworkFailedRollback_Phase3");
List<String> watchdogEvents = mLogger.getWatchdogLoggingEvents();
assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
index 35bc65a..7977b9a 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
@@ -119,15 +119,6 @@
@Test
public void testNetworkFailedRollback_Phase3() throws Exception {
- // Sleep for > health check deadline (120s to trigger rollback + 120s to reboot)
- // The device is expected to reboot during sleeping. This device method will fail and
- // the host will catch the assertion. If reboot doesn't happen, the host will fail the
- // assertion.
- Thread.sleep(TimeUnit.SECONDS.toMillis(240));
- }
-
- @Test
- public void testNetworkFailedRollback_Phase4() throws Exception {
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
getNetworkStackPackageName())).isNotNull();
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index d468076..b40d022 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -17,10 +17,9 @@
package com.android.test.taskembed;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.window.WindowOrganizer.TaskOrganizer;
-import android.app.Activity;
import android.app.ActivityManager;
+import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
@@ -35,10 +34,12 @@
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.LinearLayout;
import android.window.ITaskOrganizer;
import android.window.IWindowContainerTransactionCallback;
+import android.window.TaskOrganizer;
import android.window.WindowContainerTransaction;
+import android.widget.LinearLayout;
+import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
public class TaskOrganizerMultiWindowTest extends Activity {
@@ -97,7 +98,7 @@
class ResizingTaskView extends TaskView {
final Intent mIntent;
boolean launched = false;
- ResizingTaskView(Context c, ITaskOrganizer o, int windowingMode, Intent i) {
+ ResizingTaskView(Context c, TaskOrganizer o, int windowingMode, Intent i) {
super(c, o, windowingMode);
mIntent = i;
}
@@ -116,7 +117,7 @@
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setBounds(mWc, new Rect(0, 0, width, height));
try {
- WindowOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
+ mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
} catch (Exception e) {
// Oh well
}
@@ -127,14 +128,13 @@
TaskView mTaskView2;
boolean gotFirstTask = false;
- class Organizer extends ITaskOrganizer.Stub {
+ class Organizer extends TaskOrganizer {
private int receivedTransactions = 0;
SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
- IWindowContainerTransactionCallback mTransactionCallback =
- new IWindowContainerTransactionCallback() {
+ WindowContainerTransactionCallback mTransactionCallback =
+ new WindowContainerTransactionCallback() {
@Override
- public void transactionReady(int id, SurfaceControl.Transaction t)
- throws RemoteException {
+ public void onTransactionReady(int id, SurfaceControl.Transaction t) {
mergedTransaction.merge(t);
receivedTransactions++;
if (receivedTransactions == 2) {
@@ -142,11 +142,6 @@
receivedTransactions = 0;
}
}
-
- @Override
- public IBinder asBinder() {
- return null;
- }
};
@Override
@@ -158,14 +153,6 @@
mTaskView2.reparentTask(ti.token);
}
}
- public void onTaskVanished(ActivityManager.RunningTaskInfo ti) {
- }
- @Override
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
- }
- @Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
- }
}
Organizer mOrganizer = new Organizer();
@@ -174,10 +161,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- try {
- TaskOrganizer.registerOrganizer(mOrganizer, WINDOWING_MODE_MULTI_WINDOW);
- } catch (Exception e) {
- }
+ mOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
mTaskView1 = new ResizingTaskView(this, mOrganizer, WINDOWING_MODE_MULTI_WINDOW,
makeSettingsIntent());
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index a589d95..2a1aa2e 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -17,7 +17,6 @@
package com.android.test.taskembed;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.window.WindowOrganizer.TaskOrganizer;
import android.app.ActivityManager;
import android.app.Service;
@@ -25,11 +24,10 @@
import android.graphics.Rect;
import android.os.IBinder;
import android.view.ViewGroup;
+import android.window.TaskOrganizer;
+import android.window.WindowContainerTransaction;
import android.view.WindowManager;
import android.widget.FrameLayout;
-import android.window.ITaskOrganizer;
-import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
public class TaskOrganizerPipTest extends Service {
static final int PIP_WIDTH = 640;
@@ -37,23 +35,13 @@
TaskView mTaskView;
- class Organizer extends ITaskOrganizer.Stub {
+ class Organizer extends TaskOrganizer {
public void onTaskAppeared(ActivityManager.RunningTaskInfo ti) {
mTaskView.reparentTask(ti.token);
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.scheduleFinishEnterPip(ti.token, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
- try {
- WindowOrganizer.applyTransaction(wct);
- } catch (Exception e) {
- }
- }
- public void onTaskVanished(ActivityManager.RunningTaskInfo ti) {
- }
- public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
- }
- @Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ applyTransaction(wct);
}
}
@@ -68,10 +56,7 @@
public void onCreate() {
super.onCreate();
- try {
- TaskOrganizer.registerOrganizer(mOrganizer, WINDOWING_MODE_PINNED);
- } catch (Exception e) {
- }
+ mOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
final WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
wlp.setTitle("TaskOrganizerPipTest");
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
index 438a062..03615f3 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
@@ -18,7 +18,8 @@
import android.app.ActivityTaskManager;
import android.content.Context;
-import android.window.IWindowContainer;
+import android.window.TaskOrganizer;
+import android.window.WindowContainerToken;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
@@ -29,14 +30,14 @@
* after it's Surface is ready.
*/
class TaskView extends SurfaceView implements SurfaceHolder.Callback {
- final ITaskOrganizer mTaskOrganizer;
+ final TaskOrganizer mTaskOrganizer;
final int mWindowingMode;
- IWindowContainer mWc;
+ WindowContainerToken mWc;
boolean mSurfaceCreated = false;
boolean mNeedsReparent;
- TaskView(Context c, ITaskOrganizer o, int windowingMode) {
+ TaskView(Context c, TaskOrganizer o, int windowingMode) {
super(c);
getHolder().addCallback(this);
setZOrderOnTop(true);
@@ -62,7 +63,7 @@
public void surfaceDestroyed(SurfaceHolder holder) {
}
- void reparentTask(IWindowContainer wc) {
+ void reparentTask(WindowContainerToken wc) {
mWc = wc;
if (mSurfaceCreated == false) {
mNeedsReparent = true;
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 2b5720a..b4f0daa 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -480,6 +480,8 @@
assertEquals(1, rmnet0.getLinkAddresses().size());
assertEquals(1, rmnet0.getAllAddresses().size());
assertEquals(1, rmnet0.getAllLinkAddresses().size());
+ assertEquals(1, rmnet0.getAllInterfaceNames().size());
+ assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
rmnet0.addStackedLink(clat4);
assertEquals(1, rmnet0.getStackedLinks().size());
@@ -487,6 +489,9 @@
assertEquals(1, rmnet0.getLinkAddresses().size());
assertEquals(2, rmnet0.getAllAddresses().size());
assertEquals(2, rmnet0.getAllLinkAddresses().size());
+ assertEquals(2, rmnet0.getAllInterfaceNames().size());
+ assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
+ assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
rmnet0.addStackedLink(clat4);
assertEquals(1, rmnet0.getStackedLinks().size());
@@ -494,6 +499,9 @@
assertEquals(1, rmnet0.getLinkAddresses().size());
assertEquals(2, rmnet0.getAllAddresses().size());
assertEquals(2, rmnet0.getAllLinkAddresses().size());
+ assertEquals(2, rmnet0.getAllInterfaceNames().size());
+ assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
+ assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
assertEquals(0, clat4.getStackedLinks().size());
@@ -513,6 +521,8 @@
assertEquals(1, rmnet0.getLinkAddresses().size());
assertEquals(1, rmnet0.getAllAddresses().size());
assertEquals(1, rmnet0.getAllLinkAddresses().size());
+ assertEquals(1, rmnet0.getAllInterfaceNames().size());
+ assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
assertFalse(rmnet0.removeStackedLink("clat4"));
}
@@ -1197,4 +1207,48 @@
lp.clear();
assertNull(lp.getCaptivePortalData());
}
+
+ private LinkProperties makeIpv4LinkProperties() {
+ final LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setInterfaceName(NAME);
+ linkProperties.addLinkAddress(LINKADDRV4);
+ linkProperties.addDnsServer(DNS1);
+ linkProperties.addRoute(new RouteInfo(GATEWAY1));
+ linkProperties.addRoute(new RouteInfo(GATEWAY2));
+ return linkProperties;
+ }
+
+ private LinkProperties makeIpv6LinkProperties() {
+ final LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setInterfaceName(NAME);
+ linkProperties.addLinkAddress(LINKADDRV6);
+ linkProperties.addDnsServer(DNS6);
+ linkProperties.addRoute(new RouteInfo(GATEWAY61));
+ linkProperties.addRoute(new RouteInfo(GATEWAY62));
+ return linkProperties;
+ }
+
+ @Test
+ public void testHasIpv4DefaultRoute() {
+ final LinkProperties Ipv4 = makeIpv4LinkProperties();
+ assertTrue(Ipv4.hasIpv4DefaultRoute());
+ final LinkProperties Ipv6 = makeIpv6LinkProperties();
+ assertFalse(Ipv6.hasIpv4DefaultRoute());
+ }
+
+ @Test
+ public void testHasIpv4DnsServer() {
+ final LinkProperties Ipv4 = makeIpv4LinkProperties();
+ assertTrue(Ipv4.hasIpv4DnsServer());
+ final LinkProperties Ipv6 = makeIpv6LinkProperties();
+ assertFalse(Ipv6.hasIpv4DnsServer());
+ }
+
+ @Test
+ public void testHasIpv6DnsServer() {
+ final LinkProperties Ipv4 = makeIpv4LinkProperties();
+ assertFalse(Ipv4.hasIpv6DnsServer());
+ final LinkProperties Ipv6 = makeIpv6LinkProperties();
+ assertTrue(Ipv6.hasIpv6DnsServer());
+ }
}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
index 23caf49..eec3cdbe 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -24,7 +24,6 @@
import android.net.metrics.IpConnectivityLog
import android.net.util.SharedLog
import android.os.IBinder
-import com.android.networkstack.metrics.DataStallStatsUtils
import com.android.networkstack.netlink.TcpSocketTracker
import com.android.server.NetworkStackService
import com.android.server.NetworkStackService.NetworkMonitorConnector
@@ -91,7 +90,6 @@
mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
mock(NetworkStackService.NetworkStackServiceManager::class.java),
NetworkMonitorDeps(privateDnsBypassNetwork),
- mock(DataStallStatsUtils::class.java),
mock(TcpSocketTracker::class.java))
cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
}
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 3eabb14..54c5b90 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -39,6 +39,15 @@
return 0;
}
+static void write_java_annotation_constants(FILE* out) {
+ fprintf(out, " // Annotation constants.\n");
+
+ for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
+ fprintf(out, " public static final byte %s = %hhu;\n", name.c_str(), id);
+ }
+ fprintf(out, "\n");
+}
+
static void write_annotations(FILE* out, int argIndex,
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet) {
FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
@@ -48,32 +57,28 @@
}
const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
- fprintf(out, " if (code == %d) {\n", atomDecl->code);
+ const string atomConstant = make_constant_name(atomDecl->name);
+ fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
int resetState = -1;
int defaultState = -1;
for (const shared_ptr<Annotation>& annotation : annotations) {
- // TODO(b/151786433): Write atom constant name instead of atom id literal.
+ const string& annotationConstant =
+ ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
switch (annotation->type) {
- // TODO(b/151776731): Check for reset state annotation and only include
- // reset state when field value == default state annotation value.
case ANNOTATION_TYPE_INT:
- // TODO(b/151786433): Write annotation constant name instead of
- // annotation id literal.
if (ANNOTATION_ID_RESET_STATE == annotation->annotationId) {
resetState = annotation->value.intValue;
} else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
defaultState = annotation->value.intValue;
} else {
- fprintf(out, " builder.addIntAnnotation((byte) %d, %d);\n",
- annotation->annotationId, annotation->value.intValue);
+ fprintf(out, " builder.addIntAnnotation(%s, %d);\n",
+ annotationConstant.c_str(), annotation->value.intValue);
}
break;
case ANNOTATION_TYPE_BOOL:
- // TODO(b/151786433): Write annotation constant name instead of
- // annotation id literal.
- fprintf(out, " builder.addBooleanAnnotation((byte) %d, %s);\n",
- annotation->annotationId,
+ fprintf(out, " builder.addBooleanAnnotation(%s, %s);\n",
+ annotationConstant.c_str(),
annotation->value.boolValue ? "true" : "false");
break;
default:
@@ -81,9 +86,11 @@
}
}
if (defaultState != -1 && resetState != -1) {
+ const string& annotationConstant =
+ ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_RESET_STATE);
fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState);
- fprintf(out, " builder.addIntAnnotation((byte) %d, %d);\n",
- ANNOTATION_ID_RESET_STATE, defaultState);
+ fprintf(out, " builder.addIntAnnotation(%s, %d);\n",
+ annotationConstant.c_str(), defaultState);
fprintf(out, " }\n");
}
fprintf(out, " }\n");
@@ -311,6 +318,7 @@
write_java_atom_codes(out, atoms);
write_java_enum_values(out, atoms);
+ write_java_annotation_constants(out);
int errors = 0;
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index c0d73fa..d8db620 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -21,6 +21,16 @@
namespace android {
namespace stats_log_api_gen {
+static void write_native_annotation_constants(FILE* out) {
+ fprintf(out, "// Annotation constants.\n");
+
+ for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
+ fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id);
+ }
+ fprintf(out, "\n");
+}
+
+
static void write_annotations(FILE* out, int argIndex,
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
const string& methodPrefix, const string& methodSuffix) {
@@ -31,33 +41,31 @@
}
const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
- fprintf(out, " if (code == %d) {\n", atomDecl->code);
+ const string atomConstant = make_constant_name(atomDecl->name);
+ fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
int resetState = -1;
int defaultState = -1;
for (const shared_ptr<Annotation>& annotation : annotations) {
- // TODO(b/151786433): Write atom constant name instead of atom id literal.
+ const string& annotationConstant =
+ ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
switch (annotation->type) {
- // TODO(b/151776731): Check for reset state annotation and only include
- // reset state when field value == default state annotation value.
case ANNOTATION_TYPE_INT:
- // TODO(b/151786433): Write annotation constant name instead of
- // annotation id literal.
if (ANNOTATION_ID_RESET_STATE == annotation->annotationId) {
resetState = annotation->value.intValue;
} else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
defaultState = annotation->value.intValue;
} else {
- fprintf(out, " %saddInt32Annotation(%s%d, %d);\n",
+ fprintf(out, " %saddInt32Annotation(%s%s, %d);\n",
methodPrefix.c_str(), methodSuffix.c_str(),
- annotation->annotationId, annotation->value.intValue);
+ annotationConstant.c_str(), annotation->value.intValue);
}
break;
case ANNOTATION_TYPE_BOOL:
// TODO(b/151786433): Write annotation constant name instead of
// annotation id literal.
- fprintf(out, " %saddBoolAnnotation(%s%d, %s);\n", methodPrefix.c_str(),
- methodSuffix.c_str(), annotation->annotationId,
+ fprintf(out, " %saddBoolAnnotation(%s%s, %s);\n", methodPrefix.c_str(),
+ methodSuffix.c_str(), annotationConstant.c_str(),
annotation->value.boolValue ? "true" : "false");
break;
default:
@@ -65,9 +73,11 @@
}
}
if (defaultState != -1 && resetState != -1) {
+ const string& annotationConstant =
+ ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_RESET_STATE);
fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState);
- fprintf(out, " %saddInt32Annotation(%s%d, %d);\n", methodPrefix.c_str(),
- methodSuffix.c_str(), ANNOTATION_ID_RESET_STATE, defaultState);
+ fprintf(out, " %saddInt32Annotation(%s%s, %d);\n", methodPrefix.c_str(),
+ methodSuffix.c_str(), annotationConstant.c_str(), defaultState);
fprintf(out, " }\n");
}
fprintf(out, " }\n");
@@ -314,6 +324,8 @@
}
}
+ write_native_annotation_constants(out);
+
fprintf(out, "struct BytesField {\n");
fprintf(out,
" BytesField(char const* array, size_t len) : arg(array), "
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index 57b6f62..1f64442 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -38,6 +38,14 @@
const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
const int JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS = 0x04;
+const map<unsigned char, string> ANNOTATION_ID_CONSTANTS = {
+ { ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID" },
+ { ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP" },
+ { ANNOTATION_ID_STATE_OPTION, "ANNOTATION_ID_STATE_OPTION" },
+ { ANNOTATION_ID_RESET_STATE, "ANNOTATION_ID_RESET_STATE" },
+ { ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED" }
+};
+
string make_constant_name(const string& str);
const char* cpp_type_name(java_type_t type);