Merge "audio: Update output device name for desktop" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 8a2616e..0ca9789 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -78,6 +78,7 @@
"android.view.inputmethod.flags-aconfig-java",
"android.webkit.flags-aconfig-java",
"android.widget.flags-aconfig-java",
+ "art_exported_aconfig_flags_lib",
"backstage_power_flags_lib",
"backup_flags_lib",
"camera_platform_flags_core_java_lib",
@@ -140,6 +141,14 @@
libs: ["fake_device_config"],
}
+// ART
+java_aconfig_library {
+ name: "art_exported_aconfig_flags_lib",
+ aconfig_declarations: "art-aconfig-flags",
+ mode: "exported",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// Camera
java_aconfig_library {
name: "camera_platform_flags_core_java_lib",
diff --git a/Android.bp b/Android.bp
index 258440f..5b9f2cb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -427,6 +427,7 @@
"modules-utils-expresslog",
"perfetto_trace_javastream_protos_jarjar",
"libaconfig_java_proto_nano",
+ "aconfig_device_paths_java",
],
}
diff --git a/TEST_MAPPING b/TEST_MAPPING
index dfacbc4..e469f16 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,44 +1,17 @@
{
"presubmit-large": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksServicesTests_Presubmit"
}
],
"presubmit-pm": [
{
- "name": "PackageManagerServiceServerTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "PackageManagerServiceServerTests_Presubmit"
}
],
"presubmit": [
{
- "name": "ManagedProvisioningTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ManagedProvisioningTests"
},
{
"file_patterns": [
@@ -46,86 +19,28 @@
"SystemServer\\.java",
"services/tests/apexsystemservices/.*"
],
- "name": "ApexSystemServicesTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "ApexSystemServicesTestCases"
},
{
- "name": "FrameworksUiServicesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksUiServicesTests"
},
{
- "name": "FrameworksInputMethodSystemServerTests",
- "options": [
- {"include-filter": "com.android.server.inputmethod"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksInputMethodSystemServerTests_server_inputmethod"
},
{
- "name": "ExtServicesUnitTests-tplus",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ExtServicesUnitTests-tplus"
},
{
- "name": "ExtServicesUnitTests-sminus",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ExtServicesUnitTests-sminus"
},
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksCoreTests_Presubmit"
},
{
- "name": "FrameworkPermissionTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworkPermissionTests_Presubmit"
},
{
- "name": "FrameworksInProcessTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksInProcessTests"
},
{
"name": "vts_treble_vintf_framework_test"
@@ -166,78 +81,25 @@
// infra during the hardening phase.
// TODO: this tag to be removed once the above is no longer an issue.
{
- "name": "FrameworksUiServicesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksUiServicesTests"
},
{
- "name": "ExtServicesUnitTests-tplus",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ExtServicesUnitTests-tplus"
},
{
- "name": "ExtServicesUnitTests-sminus",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ExtServicesUnitTests-sminus"
},
{
- "name": "TestablesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TestablesTests"
},
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksCoreTests_Presubmit"
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksServicesTests_presubmit"
},
{
- "name": "PackageManagerServiceServerTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "PackageManagerServiceServerTests_Presubmit"
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
index b58cb88..e3e72f4 100644
--- a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
@@ -11,10 +11,7 @@
],
"postsubmit": [
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server"}
- ]
+ "name": "FrameworksMockingServicesTests_android_server"
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
index afa509c..ed8851c 100644
--- a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
@@ -6,10 +6,7 @@
],
"postsubmit": [
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server"}
- ]
+ "name": "FrameworksMockingServicesTests_android_server"
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index a0bf78f..d198bfd 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -1,11 +1,7 @@
{
"presubmit": [
{
- "name": "CtsJobSchedulerTestCases",
- "options": [
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"}
- ]
+ "name": "CtsJobSchedulerTestCases_com_android_server_job"
},
{
"name": "FrameworksMockingServicesTests_com_android_server_job_Presubmit"
@@ -19,26 +15,16 @@
"name": "CtsJobSchedulerTestCases"
},
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server.job"}
- ]
+ "name": "FrameworksMockingServicesTests_com_android_server_job"
},
{
"name": "FrameworksServicesTests_com_android_server_job"
},
{
- "name": "CtsHostsideNetworkPolicyTests",
- "options": [
- {"include-filter": "com.android.cts.netpolicy.HostsideRestrictBackgroundNetworkTests#testMeteredNetworkAccess_expeditedJob"},
- {"include-filter": "com.android.cts.netpolicy.HostsideRestrictBackgroundNetworkTests#testNonMeteredNetworkAccess_expeditedJob"}
- ]
+ "name": "CtsHostsideNetworkPolicyTests_com_android_server_job"
},
{
- "name": "CtsStatsdAtomHostTestCases",
- "options": [
- {"include-filter": "android.cts.statsdatom.jobscheduler"}
- ]
+ "name": "CtsStatsdAtomHostTestCases_statsdatom_jobscheduler"
}
]
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index f56c14d..1a2013d 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -1,13 +1,7 @@
{
"presubmit": [
{
- "name": "CtsUsageStatsTestCases",
- "options": [
- {"include-filter": "android.app.usage.cts.UsageStatsTest"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.MediumTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"}
- ]
+ "name": "CtsUsageStatsTestCases_cts_usagestatstest"
},
{
"name": "CtsBRSTestCases"
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index fdf9abc4..c2f6e30 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -70,8 +70,9 @@
using ui::DisplayMode;
static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
-static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "/product/media/bootanimation-dark.zip";
-static const char PRODUCT_BOOTANIMATION_FILE[] = "/product/media/bootanimation.zip";
+static const char PRODUCT_BOOTANIMATION_DIR[] = "/product/media/";
+static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "bootanimation-dark.zip";
+static const char PRODUCT_BOOTANIMATION_FILE[] = "bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
static const char APEX_BOOTANIMATION_FILE[] = "/apex/com.android.bootanimation/etc/bootanimation.zip";
static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
@@ -749,8 +750,11 @@
void BootAnimation::findBootAnimationFile() {
ATRACE_CALL();
const bool playDarkAnim = android::base::GetIntProperty("ro.boot.theme", 0) == 1;
+ const std::string productBootanimationFile = PRODUCT_BOOTANIMATION_DIR +
+ android::base::GetProperty("ro.product.bootanim.file", playDarkAnim ?
+ PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE);
static const std::vector<std::string> bootFiles = {
- APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,
+ APEX_BOOTANIMATION_FILE, productBootanimationFile,
OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE
};
static const std::vector<std::string> shutdownFiles = {
diff --git a/cmds/locksettings/TEST_MAPPING b/cmds/locksettings/TEST_MAPPING
index af54a2d..0f502c9 100644
--- a/cmds/locksettings/TEST_MAPPING
+++ b/cmds/locksettings/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit-large": [
{
- "name": "CtsDevicePolicyManagerTestCases",
- "options": [
- {
- "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- }
- ]
+ "name": "CtsDevicePolicyManagerTestCases_LockSettingsTest"
}
],
"postsubmit": [
diff --git a/cmds/screencap/Android.bp b/cmds/screencap/Android.bp
index c009c1f..16026ec 100644
--- a/cmds/screencap/Android.bp
+++ b/cmds/screencap/Android.bp
@@ -17,6 +17,7 @@
"libutils",
"libbinder",
"libjnigraphics",
+ "libhwui",
"libui",
"libgui",
],
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 01b20f4..12de82a 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -15,36 +15,28 @@
*/
#include <android/bitmap.h>
+#include <android/graphics/bitmap.h>
#include <android/gui/DisplayCaptureArgs.h>
#include <binder/ProcessState.h>
#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-
-#include <linux/fb.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-
-#include <android/bitmap.h>
-
-#include <binder/ProcessState.h>
-
#include <ftl/concat.h>
#include <ftl/optional.h>
+#include <getopt.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SyncScreenCaptureListener.h>
-
+#include <linux/fb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <system/graphics.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
-#include <system/graphics.h>
-
using namespace android;
#define COLORSPACE_UNKNOWN 0
@@ -85,11 +77,12 @@
};
}
-static const struct option LONG_OPTIONS[] = {
- {"png", no_argument, nullptr, 'p'},
- {"help", no_argument, nullptr, 'h'},
- {"hint-for-seamless", no_argument, nullptr, LongOpts::HintForSeamless},
- {0, 0, 0, 0}};
+static const struct option LONG_OPTIONS[] = {{"png", no_argument, nullptr, 'p'},
+ {"jpeg", no_argument, nullptr, 'j'},
+ {"help", no_argument, nullptr, 'h'},
+ {"hint-for-seamless", no_argument, nullptr,
+ LongOpts::HintForSeamless},
+ {0, 0, 0, 0}};
static int32_t flinger2bitmapFormat(PixelFormat f)
{
@@ -170,10 +163,11 @@
return 0;
}
-status_t saveImage(const char* fn, bool png, const ScreenCaptureResults& captureResults) {
+status_t saveImage(const char* fn, std::optional<AndroidBitmapCompressFormat> format,
+ const ScreenCaptureResults& captureResults) {
void* base = nullptr;
ui::Dataspace dataspace = captureResults.capturedDataspace;
- sp<GraphicBuffer> buffer = captureResults.buffer;
+ const sp<GraphicBuffer>& buffer = captureResults.buffer;
status_t result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
@@ -188,22 +182,48 @@
return 1;
}
+ void* gainmapBase = nullptr;
+ sp<GraphicBuffer> gainmap = captureResults.optionalGainMap;
+
+ if (gainmap) {
+ result = gainmap->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &gainmapBase);
+ if (gainmapBase == nullptr || result != NO_ERROR) {
+ fprintf(stderr, "Failed to capture gainmap with error code (%d)\n", result);
+ gainmapBase = nullptr;
+ // Fall-through: just don't attempt to write the gainmap
+ }
+ }
+
int fd = -1;
if (fn == nullptr) {
fd = dup(STDOUT_FILENO);
if (fd == -1) {
fprintf(stderr, "Error writing to stdout. (%s)\n", strerror(errno));
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
return 1;
}
} else {
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (fd == -1) {
fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
return 1;
}
}
- if (png) {
+ if (format) {
AndroidBitmapInfo info;
info.format = flinger2bitmapFormat(buffer->getPixelFormat());
info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
@@ -211,16 +231,31 @@
info.height = buffer->getHeight();
info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
- int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base,
- ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd,
+ int result;
+
+ if (gainmapBase) {
+ result = ABitmap_compressWithGainmap(&info, static_cast<ADataSpace>(dataspace), base,
+ gainmapBase, captureResults.hdrSdrRatio, *format,
+ 100, &fd,
+ [](void* fdPtr, const void* data,
+ size_t size) -> bool {
+ int bytesWritten =
+ write(*static_cast<int*>(fdPtr), data,
+ size);
+ return bytesWritten == size;
+ });
+ } else {
+ result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base, *format,
+ 100, &fd,
[](void* fdPtr, const void* data, size_t size) -> bool {
int bytesWritten = write(*static_cast<int*>(fdPtr),
data, size);
return bytesWritten == size;
});
+ }
if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
- fprintf(stderr, "Failed to compress PNG (error code: %d)\n", result);
+ fprintf(stderr, "Failed to compress (error code: %d)\n", result);
}
if (fn != NULL) {
@@ -245,6 +280,14 @@
}
close(fd);
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
+
return 0;
}
@@ -262,13 +305,17 @@
gui::CaptureArgs captureArgs;
const char* pname = argv[0];
bool png = false;
+ bool jpeg = false;
bool all = false;
int c;
- while ((c = getopt_long(argc, argv, "aphd:", LONG_OPTIONS, nullptr)) != -1) {
+ while ((c = getopt_long(argc, argv, "apjhd:", LONG_OPTIONS, nullptr)) != -1) {
switch (c) {
case 'p':
png = true;
break;
+ case 'j':
+ jpeg = true;
+ break;
case 'd': {
errno = 0;
char* end = nullptr;
@@ -325,6 +372,14 @@
baseName = filename.substr(0, filename.size()-4);
suffix = ".png";
png = true;
+ } else if (filename.ends_with(".jpeg")) {
+ baseName = filename.substr(0, filename.size() - 5);
+ suffix = ".jpeg";
+ jpeg = true;
+ } else if (filename.ends_with(".jpg")) {
+ baseName = filename.substr(0, filename.size() - 4);
+ suffix = ".jpg";
+ jpeg = true;
} else {
baseName = filename;
}
@@ -350,6 +405,20 @@
}
}
+ if (png && jpeg) {
+ fprintf(stderr, "Ambiguous file type");
+ return 1;
+ }
+
+ std::optional<AndroidBitmapCompressFormat> format = std::nullopt;
+
+ if (png) {
+ format = ANDROID_BITMAP_COMPRESS_FORMAT_PNG;
+ } else if (jpeg) {
+ format = ANDROID_BITMAP_COMPRESS_FORMAT_JPEG;
+ captureArgs.attachGainmap = true;
+ }
+
// setThreadPoolMaxThreadCount(0) actually tells the kernel it's
// not allowed to spawn any additional threads, but we still spawn
// a binder thread from userspace when we call startThreadPool().
@@ -385,7 +454,7 @@
if (!filename.empty()) {
fn = filename.c_str();
}
- if (const status_t saveImageStatus = saveImage(fn, png, result) != 0) {
+ if (const status_t saveImageStatus = saveImage(fn, format, result) != 0) {
fprintf(stderr, "Saving image failed.\n");
return saveImageStatus;
}
diff --git a/core/api/current.txt b/core/api/current.txt
index dada20e..1667f2e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6396,6 +6396,7 @@
method public android.graphics.drawable.Icon getLargeIcon();
method @Nullable public android.content.LocusId getLocusId();
method public CharSequence getSettingsText();
+ method @FlaggedApi("android.app.api_rich_ongoing") @Nullable public String getShortCriticalText();
method public String getShortcutId();
method public android.graphics.drawable.Icon getSmallIcon();
method public String getSortKey();
@@ -6719,6 +6720,7 @@
method @NonNull public android.app.Notification.Builder setPublicVersion(android.app.Notification);
method @NonNull public android.app.Notification.Builder setRemoteInputHistory(CharSequence[]);
method @NonNull public android.app.Notification.Builder setSettingsText(CharSequence);
+ method @FlaggedApi("android.app.api_rich_ongoing") @NonNull public android.app.Notification.Builder setShortCriticalText(@Nullable String);
method @NonNull public android.app.Notification.Builder setShortcutId(String);
method @NonNull public android.app.Notification.Builder setShowWhen(boolean);
method @NonNull public android.app.Notification.Builder setSmallIcon(@DrawableRes int);
@@ -16124,24 +16126,30 @@
ctor public Gainmap(@NonNull android.graphics.Bitmap);
ctor @FlaggedApi("com.android.graphics.hwui.flags.gainmap_constructor_with_metadata") public Gainmap(@NonNull android.graphics.Gainmap, @NonNull android.graphics.Bitmap);
method public int describeContents();
+ method @FlaggedApi("com.android.graphics.hwui.flags.iso_gainmap_apis") @Nullable public android.graphics.ColorSpace getAlternativeImagePrimaries();
method @NonNull public float getDisplayRatioForFullHdr();
method @NonNull public float[] getEpsilonHdr();
method @NonNull public float[] getEpsilonSdr();
method @NonNull public android.graphics.Bitmap getGainmapContents();
+ method @FlaggedApi("com.android.graphics.hwui.flags.iso_gainmap_apis") public int getGainmapDirection();
method @NonNull public float[] getGamma();
method @NonNull public float getMinDisplayRatioForHdrTransition();
method @NonNull public float[] getRatioMax();
method @NonNull public float[] getRatioMin();
+ method @FlaggedApi("com.android.graphics.hwui.flags.iso_gainmap_apis") public void setAlternativeImagePrimaries(@Nullable android.graphics.ColorSpace);
method public void setDisplayRatioForFullHdr(@FloatRange(from=1.0f) float);
method public void setEpsilonHdr(float, float, float);
method public void setEpsilonSdr(float, float, float);
method public void setGainmapContents(@NonNull android.graphics.Bitmap);
+ method @FlaggedApi("com.android.graphics.hwui.flags.iso_gainmap_apis") public void setGainmapDirection(int);
method public void setGamma(float, float, float);
method public void setMinDisplayRatioForHdrTransition(@FloatRange(from=1.0f) float);
method public void setRatioMax(float, float, float);
method public void setRatioMin(float, float, float);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.graphics.Gainmap> CREATOR;
+ field @FlaggedApi("com.android.graphics.hwui.flags.iso_gainmap_apis") public static final int GAINMAP_DIRECTION_HDR_TO_SDR = 1; // 0x1
+ field @FlaggedApi("com.android.graphics.hwui.flags.iso_gainmap_apis") public static final int GAINMAP_DIRECTION_SDR_TO_HDR = 0; // 0x0
}
public class HardwareBufferRenderer implements java.lang.AutoCloseable {
@@ -19168,7 +19176,7 @@
method @NonNull public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
method @NonNull public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailablePhysicalCameraRequestKeys();
- method @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys();
+ method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys();
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableSessionKeys();
method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeys();
method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
@@ -19205,13 +19213,13 @@
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_INFO_STRENGTH_DEFAULT_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_INFO_STRENGTH_MAXIMUM_LEVEL;
- field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL;
- field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_SINGLE_STRENGTH_MAX_LEVEL;
- field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_DEFAULT_LEVEL;
- field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_MAX_LEVEL;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_SINGLE_STRENGTH_MAX_LEVEL;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_DEFAULT_LEVEL;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_MAX_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DeviceStateSensorOrientationMap> INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP;
- field @FlaggedApi("com.android.internal.camera.flags.feature_combination_query") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.String> INFO_VERSION;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES;
@@ -19368,11 +19376,9 @@
method @NonNull public java.util.List<java.lang.Integer> getSupportedExtensions();
method public boolean isCaptureProcessProgressAvailable(int);
method public boolean isPostviewAvailable(int);
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Float>> EFV_PADDING_ZOOM_FACTOR_RANGE;
field public static final int EXTENSION_AUTOMATIC = 0; // 0x0
field @Deprecated public static final int EXTENSION_BEAUTY = 1; // 0x1
field public static final int EXTENSION_BOKEH = 2; // 0x2
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public static final int EXTENSION_EYES_FREE_VIDEOGRAPHY = 5; // 0x5
field public static final int EXTENSION_FACE_RETOUCH = 1; // 0x1
field public static final int EXTENSION_HDR = 3; // 0x3
field public static final int EXTENSION_NIGHT = 4; // 0x4
@@ -19758,7 +19764,7 @@
public final class CaptureRequest extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CaptureRequest.Key<?>> implements android.os.Parcelable {
method public int describeContents();
- method @FlaggedApi("com.android.internal.camera.flags.surface_leak_fix") protected void finalize();
+ method protected void finalize();
method @Nullable public <T> T get(android.hardware.camera2.CaptureRequest.Key<T>);
method @NonNull public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getKeys();
method @Nullable public Object getTag();
@@ -19798,7 +19804,7 @@
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> EDGE_MODE;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> EXTENSION_STRENGTH;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> FLASH_MODE;
- field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> FLASH_STRENGTH_LEVEL;
+ field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> FLASH_STRENGTH_LEVEL;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> HOT_PIXEL_MODE;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<android.location.Location> JPEG_GPS_LOCATION;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> JPEG_ORIENTATION;
@@ -19895,7 +19901,7 @@
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> EXTENSION_STRENGTH;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_MODE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_STATE;
- field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_STRENGTH_LEVEL;
+ field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_STRENGTH_LEVEL;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> HOT_PIXEL_MODE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.location.Location> JPEG_GPS_LOCATION;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> JPEG_ORIENTATION;
@@ -19972,30 +19978,6 @@
field public static final int MAX_THUMBNAIL_DIMENSION = 256; // 0x100
}
- @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public final class ExtensionCaptureRequest {
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> EFV_AUTO_ZOOM;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> EFV_MAX_PADDING_ZOOM_FACTOR;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> EFV_PADDING_ZOOM_FACTOR;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> EFV_ROTATE_VIEWPORT;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> EFV_STABILIZATION_MODE;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public static final int EFV_STABILIZATION_MODE_GIMBAL = 1; // 0x1
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public static final int EFV_STABILIZATION_MODE_LOCKED = 2; // 0x2
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public static final int EFV_STABILIZATION_MODE_OFF = 0; // 0x0
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<android.util.Pair<java.lang.Integer,java.lang.Integer>> EFV_TRANSLATE_VIEWPORT;
- }
-
- @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public final class ExtensionCaptureResult {
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> EFV_AUTO_ZOOM;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<int[]> EFV_AUTO_ZOOM_PADDING_REGION;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> EFV_MAX_PADDING_ZOOM_FACTOR;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<int[]> EFV_PADDING_REGION;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> EFV_PADDING_ZOOM_FACTOR;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> EFV_ROTATE_VIEWPORT;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> EFV_STABILIZATION_MODE;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.graphics.PointF[]> EFV_TARGET_COORDINATES;
- field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Integer,java.lang.Integer>> EFV_TRANSLATE_VIEWPORT;
- }
-
public class MultiResolutionImageReader implements java.lang.AutoCloseable {
ctor public MultiResolutionImageReader(@NonNull java.util.Collection<android.hardware.camera2.params.MultiResolutionStreamInfo>, int, @IntRange(from=1) int);
method public void close();
@@ -20081,14 +20063,14 @@
public final class ExtensionSessionConfiguration {
ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void clearColorSpace();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") @Nullable public android.graphics.ColorSpace getColorSpace();
+ method public void clearColorSpace();
+ method @Nullable public android.graphics.ColorSpace getColorSpace();
method @NonNull public java.util.concurrent.Executor getExecutor();
method public int getExtension();
method @NonNull public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
method @Nullable public android.hardware.camera2.params.OutputConfiguration getPostviewOutputConfiguration();
method @NonNull public android.hardware.camera2.CameraExtensionSession.StateCallback getStateCallback();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
+ method public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
method public void setPostviewOutputConfiguration(@Nullable android.hardware.camera2.params.OutputConfiguration);
}
@@ -20457,23 +20439,23 @@
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
- field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
- field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
- field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
- field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
- field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
- field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
- field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
- field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
- field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
- field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
- field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
- field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
- field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
- field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
- field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
- field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
- field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
+ field @Deprecated public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+ field @Deprecated public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
+ field @Deprecated public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+ field @Deprecated public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+ field @Deprecated public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
+ field @Deprecated public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
+ field @Deprecated public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+ field @Deprecated public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
+ field @Deprecated public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+ field @Deprecated public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
+ field @Deprecated public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+ field @Deprecated public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
+ field @Deprecated public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+ field @Deprecated public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+ field @Deprecated public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field @Deprecated public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
+ field @Deprecated public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
}
@Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
@@ -36320,9 +36302,9 @@
method @Deprecated public static int getTypeLabelResource(int);
field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
field @Deprecated public static final String CUSTOM_PROTOCOL = "data6";
- field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
- field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
- field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+ field @Deprecated public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field @Deprecated public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field @Deprecated public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field @Deprecated public static final String PROTOCOL = "data5";
field @Deprecated public static final int PROTOCOL_AIM = 0; // 0x0
field @Deprecated public static final int PROTOCOL_CUSTOM = -1; // 0xffffffff
@@ -36455,9 +36437,9 @@
method @Deprecated public static CharSequence getTypeLabel(android.content.res.Resources, int, @Nullable CharSequence);
method @Deprecated public static int getTypeLabelResource(int);
field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address";
- field public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
- field public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
- field public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
+ field @Deprecated public static final String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field @Deprecated public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field @Deprecated public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field @Deprecated public static final String SIP_ADDRESS = "data1";
field @Deprecated public static final int TYPE_HOME = 1; // 0x1
field @Deprecated public static final int TYPE_OTHER = 3; // 0x3
@@ -36930,15 +36912,18 @@
field public static final String CONTENT_DIRECTORY = "data";
}
- @FlaggedApi("android.provider.new_default_account_api_enabled") public static final class ContactsContract.RawContacts.DefaultAccountAndState {
- ctor public ContactsContract.RawContacts.DefaultAccountAndState(int, @Nullable android.accounts.Account);
+ @FlaggedApi("android.provider.new_default_account_api_enabled") public static final class ContactsContract.RawContacts.DefaultAccount {
+ ctor public ContactsContract.RawContacts.DefaultAccount();
+ }
+
+ @FlaggedApi("android.provider.new_default_account_api_enabled") public static final class ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState {
+ ctor public ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState(int, @Nullable android.accounts.Account);
method @Nullable public android.accounts.Account getCloudAccount();
method public int getState();
- method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccountAndState ofCloud(@NonNull android.accounts.Account);
- method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccountAndState ofLocal();
- method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccountAndState ofNotSet();
+ method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofCloud(@NonNull android.accounts.Account);
+ method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofLocal();
+ method @NonNull public static android.provider.ContactsContract.RawContacts.DefaultAccount.DefaultAccountAndState ofNotSet();
field public static final int DEFAULT_ACCOUNT_STATE_CLOUD = 3; // 0x3
- field public static final int DEFAULT_ACCOUNT_STATE_INVALID = 0; // 0x0
field public static final int DEFAULT_ACCOUNT_STATE_LOCAL = 2; // 0x2
field public static final int DEFAULT_ACCOUNT_STATE_NOT_SET = 1; // 0x1
}
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 1e94c2f..df45862 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -321,7 +321,10 @@
package android.net.wifi {
public final class WifiMigration {
- method @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static void migrateLegacyKeystoreToWifiBlobstore();
+ method @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static int migrateLegacyKeystoreToWifiBlobstore();
+ field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION = 2; // 0x2
+ field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE = 0; // 0x0
+ field @FlaggedApi("android.net.wifi.flags.legacy_keystore_to_wifi_blobstore_migration_read_only") public static final int KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED = 1; // 0x1
}
}
@@ -384,10 +387,6 @@
field public static final int DEVICE_INITIAL_SDK_INT;
}
- public class Environment {
- method @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") @NonNull public static java.io.File getDataSystemDeDirectory();
- }
-
public class IpcDataCache<Query, Result> {
ctor public IpcDataCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.os.IpcDataCache.QueryHandler<Query,Result>);
method public void disableForCurrentProcess();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 475b1e2..7a8e829 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4972,12 +4972,12 @@
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class CameraOutputSurface {
ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public CameraOutputSurface(@NonNull android.view.Surface, @NonNull android.util.Size);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public int getColorSpace();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public long getDynamicRangeProfile();
+ method public int getColorSpace();
+ method public long getDynamicRangeProfile();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public int getImageFormat();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.util.Size getSize();
method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public android.view.Surface getSurface();
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setDynamicRangeProfile(long);
+ method public void setDynamicRangeProfile(long);
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class CharacteristicsMap {
@@ -4987,7 +4987,7 @@
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class ExtensionConfiguration {
ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public ExtensionConfiguration(int, int, @NonNull java.util.List<android.hardware.camera2.extension.ExtensionOutputConfiguration>, @Nullable android.hardware.camera2.CaptureRequest);
- method @FlaggedApi("com.android.internal.camera.flags.extension_10_bit") public void setColorSpace(int);
+ method public void setColorSpace(int);
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode") public class ExtensionOutputConfiguration {
@@ -10773,6 +10773,7 @@
public class Environment {
method @NonNull public static java.io.File getDataCePackageDirectoryForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle, @NonNull String);
method @NonNull public static java.io.File getDataDePackageDirectoryForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle, @NonNull String);
+ method @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") @NonNull public static java.io.File getDataSystemDeDirectory();
method @NonNull public static java.util.Collection<java.io.File> getInternalMediaDirectories();
method @NonNull public static java.io.File getOdmDirectory();
method @NonNull public static java.io.File getOemDirectory();
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 45852c7..93a9489 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -2408,9 +2408,9 @@
* @hide
*/
@android.ravenwood.annotation.RavenwoodKeep
- public final void basicInit(Context context) {
- mInstrContext = context;
- mAppContext = context;
+ public final void basicInit(Context instrContext, Context appContext) {
+ mInstrContext = instrContext;
+ mAppContext = appContext;
}
/** @hide */
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7a36fbb..81d2c89 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1281,6 +1281,15 @@
public static final String EXTRA_BIG_TEXT = "android.bigText";
/**
+ * {@link #extras} key: very short text summarizing the most critical information contained in
+ * the notification.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+ public static final String EXTRA_SHORT_CRITICAL_TEXT = "android.shortCriticalText";
+
+ /**
* {@link #extras} key: this is the resource ID of the notification's main small icon, as
* supplied to {@link Builder#setSmallIcon(int)}.
*
@@ -4050,6 +4059,17 @@
return String.join("|", defaultStrings);
}
+
+ /**
+ * Returns the very short text summarizing the most critical information contained in the
+ * notification, or null if this field was not set.
+ */
+ @Nullable
+ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+ public String getShortCriticalText() {
+ return extras.getString(EXTRA_SHORT_CRITICAL_TEXT);
+ }
+
/**
* @hide
*/
@@ -4991,6 +5011,18 @@
}
/**
+ * Sets a very short string summarizing the most critical information contained in the
+ * notification. Suggested max length is 5 characters, and there is no guarantee how much or
+ * how little of this text will be shown.
+ */
+ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING)
+ @NonNull
+ public Builder setShortCriticalText(@Nullable String shortCriticalText) {
+ mN.extras.putString(EXTRA_SHORT_CRITICAL_TEXT, shortCriticalText);
+ return this;
+ }
+
+ /**
* Set the progress this notification represents.
*
* The platform template will represent this using a {@link ProgressBar}.
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index adeb045..cd7e40c 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -112,6 +112,7 @@
# Wallpaper
per-file *Wallpaper* = file:/core/java/android/service/wallpaper/OWNERS
+per-file wallpaper.aconfig = file:/core/java/android/service/wallpaper/OWNERS
# WindowManager
per-file *Activity* = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5147f12..03bec71 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -593,6 +593,11 @@
@Override
public TextServicesManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
+ if (ctx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
+ && ServiceManager.getService(Context.TEXT_SERVICES_MANAGER_SERVICE) == null
+ && android.server.Flags.removeTextService()) {
+ return null;
+ }
return TextServicesManager.createInstance(ctx);
}});
@@ -1662,11 +1667,20 @@
@Override
public WearableSensingManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
- IBinder iBinder = ServiceManager.getServiceOrThrow(
+ IBinder iBinder = ServiceManager.getService(
Context.WEARABLE_SENSING_SERVICE);
- IWearableSensingManager manager =
- IWearableSensingManager.Stub.asInterface(iBinder);
- return new WearableSensingManager(ctx.getOuterContext(), manager);
+ if (iBinder != null) {
+ IWearableSensingManager manager =
+ IWearableSensingManager.Stub.asInterface(iBinder);
+ return new WearableSensingManager(ctx.getOuterContext(), manager);
+ }
+ // Wear intentionally removes the service, so do not throw a
+ // ServiceNotFoundException when the service is not absent.
+ if (ctx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
+ && android.server.Flags.removeWearableSensingServiceFromWear()) {
+ return null;
+ }
+ throw new ServiceNotFoundException(Context.WEARABLE_SENSING_SERVICE);
}});
registerService(Context.ON_DEVICE_INTELLIGENCE_SERVICE, OnDeviceIntelligenceManager.class,
@@ -1887,6 +1901,12 @@
return null;
}
break;
+ case Context.TEXT_SERVICES_MANAGER_SERVICE:
+ if (android.server.Flags.removeTextService()
+ && hasSystemFeatureOpportunistic(ctx, PackageManager.FEATURE_WATCH)) {
+ return null;
+ }
+ break;
}
Slog.wtf(TAG, "Manager wrapper not available: " + name);
return null;
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 2358d67..5ed1f4e 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -16,12 +16,7 @@
},
{
"file_patterns": ["(/|^)AppOpsManager.java"],
- "name": "CtsAppOpsTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAppOpsTestCases"
},
{
"file_patterns": ["(/|^)AppOpsManager.java"],
@@ -54,12 +49,7 @@
"file_patterns": ["INotificationManager\\.aidl"]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.ToastWindowTest"
- }
- ],
+ "name": "CtsWindowManagerDeviceWindow_window_toastwindowtest",
"file_patterns": ["INotificationManager\\.aidl"]
},
{
@@ -67,42 +57,15 @@
"file_patterns": ["(/|^)InstantAppResolve[^/]*"]
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.saveui.AutofillSaveDialogTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
+ "name": "CtsAutoFillServiceTestCases_saveui_autofillsavedialogtest",
"file_patterns": ["(/|^)Activity.java"]
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.saveui.PreSimpleSaveActivityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
+ "name": "CtsAutoFillServiceTestCases_saveui_presimplesaveactivitytest",
"file_patterns": ["(/|^)Activity.java"]
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.saveui.SimpleSaveActivityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.AppModeFull"
- }
- ],
+ "name": "CtsAutoFillServiceTestCases_saveui_simplesaveactivitytest",
"file_patterns": ["(/|^)Activity.java"]
},
{
@@ -119,32 +82,10 @@
},
{
"name": "CtsLocalVoiceInteraction",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
"file_patterns": ["(/|^)VoiceInteract[^/]*"]
},
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.os.cts.StrictModeTest"
- }
- ],
+ "name": "CtsOsTestCases_cts_strictmodetest_Presubmit",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
@@ -153,12 +94,7 @@
},
{
"file_patterns": ["(/|^)LocaleManager.java"],
- "name": "CtsLocaleManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsLocaleManagerTestCases"
},
{
"name": "FrameworksCoreTests_keyguard_manager",
@@ -173,172 +109,51 @@
]
},
{
- "name": "FrameworksCoreGameManagerTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.app"
- }
- ],
+ "name": "FrameworksCoreGameManagerTests_android_app",
"file_patterns": [
"(/|^)GameManager[^/]*", "(/|^)GameMode[^/]*"
]
},
{
- "name": "HdmiCecTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.hardware.hdmi"
- }
- ],
+ "name": "HdmiCecTests_hardware_hdmi",
"file_patterns": [
"(/|^)DeviceFeature[^/]*", "(/|^)Hdmi[^/]*"
]
},
{
- "name": "CtsWindowManagerDeviceActivity",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceActivity_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceAm",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceAm_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceBackNavigation",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceBackNavigation_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceDisplay",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceDisplay_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceKeyguard",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceKeyguard_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceInsets",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceInsets_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceTaskFragment",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceTaskFragment_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceWindow_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
- "name": "CtsWindowManagerDeviceOther",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.wm.cts"
- }
- ],
+ "name": "CtsWindowManagerDeviceOther_wm_cts",
"file_patterns": ["(/|^)ContextImpl.java"]
},
{
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 081dfe6..d9f886d 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -134,6 +134,14 @@
bug: "364338410"
}
+flag {
+ name: "lock_now_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for lockNow."
+ bug: "366559840"
+}
+
# Fully rolled out and must not be used.
flag {
name: "security_log_v2_enabled"
@@ -323,3 +331,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "user_provisioning_same_state"
+ namespace: "enterprise"
+ description: "Handle exceptions while setting same provisioning state."
+ bug: "326441417"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
index f5c5a11..36daaab 100644
--- a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
+++ b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
@@ -180,13 +180,8 @@
*
* @param packageName the name of the package that owns the function.
* @param functionId the id of the function.
- * @param staticMetadataQualifiedId the qualified static metadata id that this runtime
- * metadata refers to.
*/
- public Builder(
- @NonNull String packageName,
- @NonNull String functionId,
- @NonNull String staticMetadataQualifiedId) {
+ public Builder(@NonNull String packageName, @NonNull String functionId) {
super(
APP_FUNCTION_RUNTIME_NAMESPACE,
getDocumentIdForAppFunction(
@@ -198,7 +193,9 @@
// Set qualified id automatically
setPropertyString(
- PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID, staticMetadataQualifiedId);
+ PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID,
+ AppFunctionStaticMetadataHelper.getStaticMetadataQualifiedId(
+ packageName, functionId));
}
/**
diff --git a/core/java/android/app/appfunctions/TEST_MAPPING b/core/java/android/app/appfunctions/TEST_MAPPING
new file mode 100644
index 0000000..91e82ec
--- /dev/null
+++ b/core/java/android/app/appfunctions/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "postsubmit": [
+ {
+ "name": "FrameworksAppFunctionsTests"
+ },
+ {
+ "name": "CtsAppFunctionTestCases"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/java/android/app/time/TEST_MAPPING b/core/java/android/app/time/TEST_MAPPING
index 7673aca..9e416385 100644
--- a/core/java/android/app/time/TEST_MAPPING
+++ b/core/java/android/app/time/TEST_MAPPING
@@ -1,31 +1,13 @@
{
"presubmit": [
{
- "name": "FrameworksTimeCoreTests",
- "options": [
- {
- "include-filter": "android.app."
- }
- ]
+ "name": "FrameworksTimeCoreTests_android_app"
},
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
- "name": "FrameworksTimeServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timezonedetector."
- },
- {
- "include-filter": "com.android.server.timedetector."
- }
- ]
+ "name": "FrameworksTimeServicesTests_time"
}
]
}
diff --git a/core/java/android/app/timedetector/TEST_MAPPING b/core/java/android/app/timedetector/TEST_MAPPING
index c7ca6a2..d876308 100644
--- a/core/java/android/app/timedetector/TEST_MAPPING
+++ b/core/java/android/app/timedetector/TEST_MAPPING
@@ -1,28 +1,13 @@
{
"presubmit": [
{
- "name": "FrameworksTimeCoreTests",
- "options": [
- {
- "include-filter": "android.app."
- }
- ]
+ "name": "FrameworksTimeCoreTests_android_app"
},
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
- "name": "FrameworksTimeServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timedetector."
- }
- ]
+ "name": "FrameworksTimeServicesTests_server_timedetector"
}
]
}
diff --git a/core/java/android/app/timezonedetector/TEST_MAPPING b/core/java/android/app/timezonedetector/TEST_MAPPING
index c8d0bb2..dca7bbf 100644
--- a/core/java/android/app/timezonedetector/TEST_MAPPING
+++ b/core/java/android/app/timezonedetector/TEST_MAPPING
@@ -1,28 +1,13 @@
{
"presubmit": [
{
- "name": "FrameworksTimeCoreTests",
- "options": [
- {
- "include-filter": "android.app."
- }
- ]
+ "name": "FrameworksTimeCoreTests_android_app"
},
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
- "name": "FrameworksTimeServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.timezonedetector."
- }
- ]
+ "name": "FrameworksTimeServicesTests_server_timezonedetector"
}
]
}
diff --git a/core/java/android/app/trust/TEST_MAPPING b/core/java/android/app/trust/TEST_MAPPING
index 23923ee..b0dd551 100644
--- a/core/java/android/app/trust/TEST_MAPPING
+++ b/core/java/android/app/trust/TEST_MAPPING
@@ -1,28 +1,12 @@
{
"presubmit": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
],
"trust-tablet": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
]
}
\ No newline at end of file
diff --git a/core/java/android/app/wallpaper.aconfig b/core/java/android/app/wallpaper.aconfig
new file mode 100644
index 0000000..4091622
--- /dev/null
+++ b/core/java/android/app/wallpaper.aconfig
@@ -0,0 +1,8 @@
+package: "android.app"
+container: "system"
+flag {
+ name: "remove_next_wallpaper_component"
+ namespace: "systemui"
+ description: "Remove deprecated field WallpaperData#nextWallpaperComponent. Only effective after rebooting."
+ bug: "365991991"
+}
diff --git a/core/java/android/companion/IOnAssociationsChangedListener.aidl b/core/java/android/companion/IOnAssociationsChangedListener.aidl
index d369456..eba3804 100644
--- a/core/java/android/companion/IOnAssociationsChangedListener.aidl
+++ b/core/java/android/companion/IOnAssociationsChangedListener.aidl
@@ -19,23 +19,6 @@
import android.companion.AssociationInfo;
/** @hide */
-interface IOnAssociationsChangedListener {
-
- /*
- * IMPORTANT: This method is intentionally NOT "oneway".
- *
- * The method is intentionally "blocking" to make sure that the clients of the
- * addOnAssociationsChangedListener() API (@SystemAPI guarded by a "signature" permission) are
- * able to prevent race conditions that may arise if their own clients (applications)
- * effectively get notified about the changes before system services do.
- *
- * This is safe for 2 reasons:
- * 1. The addOnAssociationsChangedListener() is only available to the system components
- * (guarded by a "signature" permission).
- * See android.permission.MANAGE_COMPANION_DEVICES.
- * 2. On the Java side addOnAssociationsChangedListener() in CDM takes an Executor, and the
- * proxy implementation of onAssociationsChanged() simply "post" a Runnable to it.
- * See CompanionDeviceManager.OnAssociationsChangedListenerProxy class.
- */
+oneway interface IOnAssociationsChangedListener {
void onAssociationsChanged(in List<AssociationInfo> associations);
}
\ No newline at end of file
diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING
index e353a01..8d90b02 100644
--- a/core/java/android/content/TEST_MAPPING
+++ b/core/java/android/content/TEST_MAPPING
@@ -1,24 +1,7 @@
{
"presubmit": [
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.os.cts.StrictModeTest"
- }
- ],
+ "name": "CtsOsTestCases_cts_strictmodetest_Presubmit",
"file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
},
{
diff --git a/core/java/android/content/om/TEST_MAPPING b/core/java/android/content/om/TEST_MAPPING
index 82c47a0..b36c895 100644
--- a/core/java/android/content/om/TEST_MAPPING
+++ b/core/java/android/content/om/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.om"
- }
- ]
+ "name": "FrameworksServicesTests_server_om"
},
{
"name": "OverlayDeviceTests"
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 52c84dc..26f919f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -778,8 +778,18 @@
public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
logErrorForInvalidProfileAccess(user);
try {
- return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
- packageName, user), user);
+ final List<LauncherActivityInfo> activityList = convertToActivityList(
+ mService.getLauncherActivities(
+ mContext.getPackageName(),
+ packageName,
+ user
+ ), user);
+ if (activityList.isEmpty()) {
+ // b/350144057
+ Log.d(TAG, "getActivityList: No launchable activities found for"
+ + "packageName=" + packageName + ", user=" + user);
+ }
+ return activityList;
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 26bb6e4..fb2655c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8842,6 +8842,7 @@
try {
ParsedPackage pp = parser2.parsePackage(apkFile, parserFlags, false);
+ pp.hideAsFinal();
return PackageInfoCommonUtils.generate(pp, flagsBits, UserHandle.myUserId());
} catch (PackageParserException e) {
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 9eec7a4..34f3b61 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -241,6 +241,16 @@
is_fixed_read_only: true
}
+flag {
+ name: "caches_not_invalidated_at_start_read_only"
+ namespace: "multiuser"
+ description: "PIC need to be invalidated at start in order to work properly."
+ bug: "356167673"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ is_fixed_read_only: true
+}
# This flag guards the private space feature and all its implementations excluding the APIs. APIs are guarded by android.os.Flags.allow_private_profile.
flag {
diff --git a/core/java/android/content/pm/verify/domain/TEST_MAPPING b/core/java/android/content/pm/verify/domain/TEST_MAPPING
index 8a1982a..db98c40 100644
--- a/core/java/android/content/pm/verify/domain/TEST_MAPPING
+++ b/core/java/android/content/pm/verify/domain/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "PackageManagerServiceUnitTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.test.verify.domain"
- }
- ]
+ "name": "PackageManagerServiceUnitTests_verify_domain"
},
{
"name": "CtsDomainVerificationDeviceStandaloneTestCases"
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index ce0f9f59..8c87ad3 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -278,6 +278,17 @@
}
/**
+ * @hide
+ */
+ private static NativeAllocationRegistry getRegistry(long size) {
+ final long func = nGetNativeFinalizer();
+ final Class cls = HardwareBuffer.class;
+ return com.android.libcore.Flags.nativeMetrics()
+ ? NativeAllocationRegistry.createNonmalloced(cls, func, size)
+ : NativeAllocationRegistry.createNonmalloced(cls.getClassLoader(), func, size);
+ }
+
+ /**
* Private use only. See {@link #create(int, int, int, int, long)}. May also be
* called from JNI using an already allocated native <code>HardwareBuffer</code>.
*/
@@ -285,10 +296,7 @@
private HardwareBuffer(long nativeObject) {
mNativeObject = nativeObject;
long bufferSize = nEstimateSize(nativeObject);
- ClassLoader loader = HardwareBuffer.class.getClassLoader();
- NativeAllocationRegistry registry = new NativeAllocationRegistry(
- loader, nGetNativeFinalizer(), bufferSize);
- mCleaner = registry.registerNativeAllocation(this, mNativeObject);
+ mCleaner = getRegistry(bufferSize).registerNativeAllocation(this, mNativeObject);
mCloseGuard.open("HardwareBuffer.close");
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 056ca93..37983df 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -567,7 +567,6 @@
* @see #INFO_SESSION_CONFIGURATION_QUERY_VERSION
*/
@NonNull
- @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
public List<CameraCharacteristics.Key<?>> getAvailableSessionCharacteristicsKeys() {
if (mAvailableSessionCharacteristicsKeys != null) {
return mAvailableSessionCharacteristicsKeys;
@@ -1485,7 +1484,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
public static final Key<Integer> FLASH_SINGLE_STRENGTH_MAX_LEVEL =
new Key<Integer>("android.flash.singleStrengthMaxLevel", int.class);
@@ -1501,7 +1499,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
public static final Key<Integer> FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL =
new Key<Integer>("android.flash.singleStrengthDefaultLevel", int.class);
@@ -1525,7 +1522,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
public static final Key<Integer> FLASH_TORCH_STRENGTH_MAX_LEVEL =
new Key<Integer>("android.flash.torchStrengthMaxLevel", int.class);
@@ -1541,7 +1537,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
public static final Key<Integer> FLASH_TORCH_STRENGTH_DEFAULT_LEVEL =
new Key<Integer>("android.flash.torchStrengthDefaultLevel", int.class);
@@ -5210,7 +5205,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_FEATURE_COMBINATION_QUERY)
public static final Key<Integer> INFO_SESSION_CONFIGURATION_QUERY_VERSION =
new Key<Integer>("android.info.sessionConfigurationQueryVersion", int.class);
@@ -5978,28 +5972,6 @@
public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION =
new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.jpegr.availableJpegRStallDurationsMaximumResolution", android.hardware.camera2.params.StreamConfigurationDuration[].class);
- /**
- * <p>Minimum and maximum padding zoom factors supported by this camera device for
- * android.efv.paddingZoomFactor used for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension.</p>
- * <p>The minimum and maximum padding zoom factors supported by the device for
- * android.efv.paddingZoomFactor used as part of the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension feature. This extension specific camera characteristic can be queried using
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#get }.</p>
- * <p><b>Units</b>: A pair of padding zoom factors in floating-points:
- * (minPaddingZoomFactor, maxPaddingZoomFactor)</p>
- * <p><b>Range of valid values:</b><br></p>
- * <p>1.0 < minPaddingZoomFactor <= maxPaddingZoomFactor</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<android.util.Range<Float>> EFV_PADDING_ZOOM_FACTOR_RANGE =
- new Key<android.util.Range<Float>>("android.efv.paddingZoomFactorRange", new TypeReference<android.util.Range<Float>>() {{ }});
-
/**
* Mapping from INFO_SESSION_CONFIGURATION_QUERY_VERSION to session characteristics key.
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 04a810a..9b87df9 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -141,12 +141,6 @@
public static final int EXTENSION_NIGHT = 4;
/**
- * An extension that aims to lock and stabilize a given region or object of interest.
- */
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final int EXTENSION_EYES_FREE_VIDEOGRAPHY = 5;
-
- /**
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@@ -154,8 +148,7 @@
EXTENSION_FACE_RETOUCH,
EXTENSION_BOKEH,
EXTENSION_HDR,
- EXTENSION_NIGHT,
- EXTENSION_EYES_FREE_VIDEOGRAPHY})
+ EXTENSION_NIGHT})
public @interface Extension {
}
@@ -634,9 +627,6 @@
public ExtensionConnectionManager() {
IntArray extensionList = new IntArray(EXTENSION_LIST.length);
extensionList.addAll(EXTENSION_LIST);
- if (Flags.concertModeApi()) {
- extensionList.add(EXTENSION_EYES_FREE_VIDEOGRAPHY);
- }
for (int extensionType : extensionList.toArray()) {
mConnections.put(extensionType, new ExtensionConnection());
@@ -837,9 +827,6 @@
IntArray extensionList = new IntArray(EXTENSION_LIST.length);
extensionList.addAll(EXTENSION_LIST);
- if (Flags.concertModeApi()) {
- extensionList.add(EXTENSION_EYES_FREE_VIDEOGRAPHY);
- }
for (int extensionType : extensionList.toArray()) {
try {
@@ -1598,28 +1585,4 @@
return Collections.unmodifiableSet(ret);
}
-
-
- /**
- * <p>Minimum and maximum padding zoom factors supported by this camera device for
- * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } used for
- * the {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension.</p>
- * <p>The minimum and maximum padding zoom factors supported by the device for
- * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } used as part of the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension feature. This extension specific camera characteristic can be queried using
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#get}.</p>
- * <p><b>Units</b>: A pair of padding zoom factors in floating-points:
- * (minPaddingZoomFactor, maxPaddingZoomFactor)</p>
- * <p><b>Range of valid values:</b><br></p>
- * <p>1.0 < minPaddingZoomFactor <= maxPaddingZoomFactor</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<android.util.Range<Float>> EFV_PADDING_ZOOM_FACTOR_RANGE =
- CameraCharacteristics.EFV_PADDING_ZOOM_FACTOR_RANGE;
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4819f67..a69a371 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -3897,36 +3897,6 @@
public static final int DISTORTION_CORRECTION_MODE_HIGH_QUALITY = 2;
//
- // Enumeration values for CaptureRequest#EFV_STABILIZATION_MODE
- //
-
- /**
- * <p>No stabilization.</p>
- * @see CaptureRequest#EFV_STABILIZATION_MODE
- * @hide
- */
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final int EFV_STABILIZATION_MODE_OFF = 0;
-
- /**
- * <p>Gimbal stabilization mode.</p>
- * @see CaptureRequest#EFV_STABILIZATION_MODE
- * @hide
- */
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final int EFV_STABILIZATION_MODE_GIMBAL = 1;
-
- /**
- * <p>Locked stabilization mode which uses the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * stabilization to directionally steady the target region.</p>
- * @see CaptureRequest#EFV_STABILIZATION_MODE
- * @hide
- */
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final int EFV_STABILIZATION_MODE_LOCKED = 2;
-
- //
// Enumeration values for CaptureResult#CONTROL_AE_STATE
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index ac72116..3f5ae91 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -612,9 +612,7 @@
Parcelable[] parcelableArray = in.readParcelableArray(Surface.class.getClassLoader(),
Surface.class);
if (parcelableArray != null) {
- if (Flags.surfaceLeakFix()) {
- mReleaseSurfaces = true;
- }
+ mReleaseSurfaces = true;
for (Parcelable p : parcelableArray) {
Surface s = (Surface) p;
mSurfaceSet.add(s);
@@ -798,7 +796,6 @@
}
@SuppressWarnings("Finalize")
- @FlaggedApi(Flags.FLAG_SURFACE_LEAK_FIX)
@Override
protected void finalize() {
if (mReleaseSurfaces) {
@@ -2733,7 +2730,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
public static final Key<Integer> FLASH_STRENGTH_LEVEL =
new Key<Integer>("android.flash.strengthLevel", int.class);
@@ -4328,146 +4324,6 @@
public static final Key<Integer> EXTENSION_STRENGTH =
new Key<Integer>("android.extension.strength", int.class);
- /**
- * <p>Used to apply an additional digital zoom factor for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>For the {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * feature, an additional zoom factor is applied on top of the existing {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}.
- * This additional zoom factor serves as a buffer to provide more flexibility for the
- * {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED }
- * mode. If android.efv.paddingZoomFactor is not set, the default will be used.
- * The effectiveness of the stabilization may be influenced by the amount of padding zoom
- * applied. A higher padding zoom factor can stabilize the target region more effectively
- * with greater flexibility but may potentially impact image quality. Conversely, a lower
- * padding zoom factor may be used to prioritize preserving image quality, albeit with less
- * leeway in stabilizing the target region. It is recommended to set the
- * android.efv.paddingZoomFactor to at least 1.5.</p>
- * <p>If android.efv.autoZoom is enabled, the requested android.efv.paddingZoomFactor will be overridden.
- * android.efv.maxPaddingZoomFactor can be checked for more details on controlling the
- * padding zoom factor during android.efv.autoZoom.</p>
- * <p><b>Range of valid values:</b><br>
- * android.efv.paddingZoomFactorRange</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see CaptureRequest#CONTROL_ZOOM_RATIO
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_PADDING_ZOOM_FACTOR =
- new Key<Float>("android.efv.paddingZoomFactor", float.class);
-
- /**
- * <p>Used to enable or disable auto zoom for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>Turn on auto zoom to let the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * feature decide at any given point a combination of
- * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} and android.efv.paddingZoomFactor
- * to keep the target region in view and stabilized. The combination chosen by the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * will equal the requested {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} multiplied with the requested
- * android.efv.paddingZoomFactor. A limit can be set on the padding zoom if wanting
- * to control image quality further using android.efv.maxPaddingZoomFactor.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see CaptureRequest#CONTROL_ZOOM_RATIO
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Boolean> EFV_AUTO_ZOOM =
- new Key<Boolean>("android.efv.autoZoom", boolean.class);
-
- /**
- * <p>Used to limit the android.efv.paddingZoomFactor if
- * android.efv.autoZoom is enabled for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>If android.efv.autoZoom is enabled, this key can be used to set a limit
- * on the android.efv.paddingZoomFactor chosen by the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode
- * to control image quality.</p>
- * <p><b>Range of valid values:</b><br>
- * The range of android.efv.paddingZoomFactorRange. Use a value greater than or equal to
- * the android.efv.paddingZoomFactor to effectively utilize this key.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_MAX_PADDING_ZOOM_FACTOR =
- new Key<Float>("android.efv.maxPaddingZoomFactor", float.class);
-
- /**
- * <p>Set the stabilization mode for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension</p>
- * <p>The desired stabilization mode. Gimbal stabilization mode provides simple, non-locked
- * video stabilization. Locked mode uses the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * stabilization feature to fixate on the current region, utilizing it as the target area for
- * stabilization.</p>
- * <p><b>Possible values:</b></p>
- * <ul>
- * <li>{@link #EFV_STABILIZATION_MODE_OFF OFF}</li>
- * <li>{@link #EFV_STABILIZATION_MODE_GIMBAL GIMBAL}</li>
- * <li>{@link #EFV_STABILIZATION_MODE_LOCKED LOCKED}</li>
- * </ul>
- *
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @see #EFV_STABILIZATION_MODE_OFF
- * @see #EFV_STABILIZATION_MODE_GIMBAL
- * @see #EFV_STABILIZATION_MODE_LOCKED
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Integer> EFV_STABILIZATION_MODE =
- new Key<Integer>("android.efv.stabilizationMode", int.class);
-
- /**
- * <p>Used to update the target region for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>A android.util.Pair<Integer,Integer> that represents the desired
- * <Horizontal,Vertical> shift of the current locked view (or target region) in
- * pixels. Negative values indicate left and upward shifts, while positive values indicate
- * right and downward shifts in the active array coordinate system.</p>
- * <p><b>Range of valid values:</b><br>
- * android.util.Pair<Integer,Integer> represents the
- * <Horizontal,Vertical> shift. The range for the horizontal shift is
- * [-max(android.efv.paddingRegion-left), max(android.efv.paddingRegion-right)].
- * The range for the vertical shift is
- * [-max(android.efv.paddingRegion-top), max(android.efv.paddingRegion-bottom)]</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<android.util.Pair<Integer,Integer>> EFV_TRANSLATE_VIEWPORT =
- new Key<android.util.Pair<Integer,Integer>>("android.efv.translateViewport", new TypeReference<android.util.Pair<Integer,Integer>>() {{ }});
-
- /**
- * <p>Representing the desired clockwise rotation
- * of the target region in degrees for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>Value representing the desired clockwise rotation of the target
- * region in degrees.</p>
- * <p><b>Range of valid values:</b><br>
- * 0 to 360</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_ROTATE_VIEWPORT =
- new Key<Float>("android.efv.rotateViewport", float.class);
-
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 34ce92c..75d617c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3022,7 +3022,6 @@
*/
@PublicKey
@NonNull
- @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
public static final Key<Integer> FLASH_STRENGTH_LEVEL =
new Key<Integer>("android.flash.strengthLevel", int.class);
@@ -5940,214 +5939,6 @@
public static final Key<Integer> EXTENSION_STRENGTH =
new Key<Integer>("android.extension.strength", int.class);
- /**
- * <p>The padding region for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>An array [left, top, right, bottom] of the padding in pixels remaining on all four sides
- * before the target region starts to go out of bounds.</p>
- * <p>The padding region denotes the area surrounding the stabilized target region within which
- * the camera can be moved while maintaining the target region in view. As the camera moves,
- * the padding region adjusts to represent the proximity of the target region to the
- * boundary, which is the point at which the target region will start to go out of bounds.</p>
- * <p><b>Range of valid values:</b><br>
- * The padding is the number of remaining pixels of padding in each direction.
- * The pixels reference the active array coordinate system. Negative values indicate the target
- * region is out of bounds. The value for this key may be null for when the stabilization mode is
- * in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_OFF }
- * or {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_GIMBAL } mode.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<int[]> EFV_PADDING_REGION =
- new Key<int[]>("android.efv.paddingRegion", int[].class);
-
- /**
- * <p>The padding region when android.efv.autoZoom is enabled for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>An array [left, top, right, bottom] of the padding in pixels remaining on all four sides
- * before the target region starts to go out of bounds.</p>
- * <p>This may differ from android.efv.paddingRegion as the field of view can change
- * during android.efv.autoZoom, altering the boundary region and thus updating the padding between the
- * target region and the boundary.</p>
- * <p><b>Range of valid values:</b><br>
- * The padding is the number of remaining pixels of padding in each direction
- * when android.efv.autoZoom is enabled. Negative values indicate the target region is out of bounds.
- * The value for this key may be null for when the android.efv.autoZoom is not enabled.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<int[]> EFV_AUTO_ZOOM_PADDING_REGION =
- new Key<int[]>("android.efv.autoZoomPaddingRegion", int[].class);
-
- /**
- * <p>List of coordinates representing the target region relative to the
- * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE }
- * for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in
- * {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>A list of android.graphics.PointF that define the coordinates of the target region
- * relative to the
- * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE }.
- * The array represents the target region coordinates as: top-left, top-right, bottom-left,
- * bottom-right.</p>
- * <p><b>Range of valid values:</b><br>
- * The list of target coordinates will define a region within the bounds of the
- * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE }</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<android.graphics.PointF[]> EFV_TARGET_COORDINATES =
- new Key<android.graphics.PointF[]>("android.efv.targetCoordinates", android.graphics.PointF[].class);
-
- /**
- * <p>Used to apply an additional digital zoom factor for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>For the {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * feature, an additional zoom factor is applied on top of the existing {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}.
- * This additional zoom factor serves as a buffer to provide more flexibility for the
- * {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED }
- * mode. If android.efv.paddingZoomFactor is not set, the default will be used.
- * The effectiveness of the stabilization may be influenced by the amount of padding zoom
- * applied. A higher padding zoom factor can stabilize the target region more effectively
- * with greater flexibility but may potentially impact image quality. Conversely, a lower
- * padding zoom factor may be used to prioritize preserving image quality, albeit with less
- * leeway in stabilizing the target region. It is recommended to set the
- * android.efv.paddingZoomFactor to at least 1.5.</p>
- * <p>If android.efv.autoZoom is enabled, the requested android.efv.paddingZoomFactor will be overridden.
- * android.efv.maxPaddingZoomFactor can be checked for more details on controlling the
- * padding zoom factor during android.efv.autoZoom.</p>
- * <p><b>Range of valid values:</b><br>
- * android.efv.paddingZoomFactorRange</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see CaptureRequest#CONTROL_ZOOM_RATIO
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_PADDING_ZOOM_FACTOR =
- new Key<Float>("android.efv.paddingZoomFactor", float.class);
-
- /**
- * <p>Set the stabilization mode for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension</p>
- * <p>The desired stabilization mode. Gimbal stabilization mode provides simple, non-locked
- * video stabilization. Locked mode uses the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * stabilization feature to fixate on the current region, utilizing it as the target area for
- * stabilization.</p>
- * <p><b>Possible values:</b></p>
- * <ul>
- * <li>{@link #EFV_STABILIZATION_MODE_OFF OFF}</li>
- * <li>{@link #EFV_STABILIZATION_MODE_GIMBAL GIMBAL}</li>
- * <li>{@link #EFV_STABILIZATION_MODE_LOCKED LOCKED}</li>
- * </ul>
- *
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @see #EFV_STABILIZATION_MODE_OFF
- * @see #EFV_STABILIZATION_MODE_GIMBAL
- * @see #EFV_STABILIZATION_MODE_LOCKED
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Integer> EFV_STABILIZATION_MODE =
- new Key<Integer>("android.efv.stabilizationMode", int.class);
-
- /**
- * <p>Used to enable or disable auto zoom for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>Turn on auto zoom to let the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * feature decide at any given point a combination of
- * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} and android.efv.paddingZoomFactor
- * to keep the target region in view and stabilized. The combination chosen by the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * will equal the requested {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} multiplied with the requested
- * android.efv.paddingZoomFactor. A limit can be set on the padding zoom if wanting
- * to control image quality further using android.efv.maxPaddingZoomFactor.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see CaptureRequest#CONTROL_ZOOM_RATIO
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Boolean> EFV_AUTO_ZOOM =
- new Key<Boolean>("android.efv.autoZoom", boolean.class);
-
- /**
- * <p>Representing the desired clockwise rotation
- * of the target region in degrees for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>Value representing the desired clockwise rotation of the target
- * region in degrees.</p>
- * <p><b>Range of valid values:</b><br>
- * 0 to 360</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_ROTATE_VIEWPORT =
- new Key<Float>("android.efv.rotateViewport", float.class);
-
- /**
- * <p>Used to update the target region for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>A android.util.Pair<Integer,Integer> that represents the desired
- * <Horizontal,Vertical> shift of the current locked view (or target region) in
- * pixels. Negative values indicate left and upward shifts, while positive values indicate
- * right and downward shifts in the active array coordinate system.</p>
- * <p><b>Range of valid values:</b><br>
- * android.util.Pair<Integer,Integer> represents the
- * <Horizontal,Vertical> shift. The range for the horizontal shift is
- * [-max(android.efv.paddingRegion-left), max(android.efv.paddingRegion-right)].
- * The range for the vertical shift is
- * [-max(android.efv.paddingRegion-top), max(android.efv.paddingRegion-bottom)]</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<android.util.Pair<Integer,Integer>> EFV_TRANSLATE_VIEWPORT =
- new Key<android.util.Pair<Integer,Integer>>("android.efv.translateViewport", new TypeReference<android.util.Pair<Integer,Integer>>() {{ }});
-
- /**
- * <p>Used to limit the android.efv.paddingZoomFactor if
- * android.efv.autoZoom is enabled for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>If android.efv.autoZoom is enabled, this key can be used to set a limit
- * on the android.efv.paddingZoomFactor chosen by the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.CameraMetadata#EFV_STABILIZATION_MODE_LOCKED } mode
- * to control image quality.</p>
- * <p><b>Range of valid values:</b><br>
- * The range of android.efv.paddingZoomFactorRange. Use a value greater than or equal to
- * the android.efv.paddingZoomFactor to effectively utilize this key.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @hide
- */
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_MAX_PADDING_ZOOM_FACTOR =
- new Key<Float>("android.efv.maxPaddingZoomFactor", float.class);
-
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/ExtensionCaptureRequest.java b/core/java/android/hardware/camera2/ExtensionCaptureRequest.java
deleted file mode 100644
index b681ce4..0000000
--- a/core/java/android/hardware/camera2/ExtensionCaptureRequest.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureRequest.Key;
-import android.hardware.camera2.impl.ExtensionKey;
-import android.hardware.camera2.impl.PublicKey;
-
-import com.android.internal.camera.flags.Flags;
-
-/**
- * ExtensionCaptureRequest contains definitions for extension-specific CaptureRequest keys that
- * can be used to configure a {@link android.hardware.camera2.CaptureRequest} during a
- * {@link android.hardware.camera2.CameraExtensionSession}.
- *
- * Note that ExtensionCaptureRequest is not intended to be used as a replacement
- * for CaptureRequest in the extensions. It serves as a supplementary class providing
- * extension-specific CaptureRequest keys. Developers should use these keys in conjunction
- * with regular CaptureRequest objects during a
- * {@link android.hardware.camera2.CameraExtensionSession}.
- *
- * @see CaptureRequest
- * @see CameraExtensionSession
- */
-@FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
-public final class ExtensionCaptureRequest {
-
- /** To avoid exposing constructor */
- private ExtensionCaptureRequest() {}
-
- /**
- * <p>Used to apply an additional digital zoom factor for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>For the {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * feature, an additional zoom factor is applied on top of the existing {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}.
- * This additional zoom factor serves as a buffer to provide more flexibility for the
- * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED }
- * mode. If {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } is not set, the default will be used.
- * The effectiveness of the stabilization may be influenced by the amount of padding zoom
- * applied. A higher padding zoom factor can stabilize the target region more effectively
- * with greater flexibility but may potentially impact image quality. Conversely, a lower
- * padding zoom factor may be used to prioritize preserving image quality, albeit with less
- * leeway in stabilizing the target region. It is recommended to set the
- * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } to at least 1.5.</p>
- * <p>If {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is enabled, the requested {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } will be overridden.
- * {@link ExtensionCaptureRequest#EFV_MAX_PADDING_ZOOM_FACTOR } can be checked for more details on controlling the
- * padding zoom factor during {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM }.</p>
- * <p><b>Range of valid values:</b><br>
- * {@link CameraExtensionCharacteristics#EFV_PADDING_ZOOM_FACTOR_RANGE }</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see CaptureRequest#CONTROL_ZOOM_RATIO
- * @see ExtensionCaptureRequest#EFV_AUTO_ZOOM
- * @see ExtensionCaptureRequest#EFV_MAX_PADDING_ZOOM_FACTOR
- * @see ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR
- * @see CameraExtensionCharacteristics#EFV_PADDING_ZOOM_FACTOR_RANGE
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_PADDING_ZOOM_FACTOR = CaptureRequest.EFV_PADDING_ZOOM_FACTOR;
-
- /**
- * <p>Used to enable or disable auto zoom for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>Turn on auto zoom to let the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * feature decide at any given point a combination of
- * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} and {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR }
- * to keep the target region in view and stabilized. The combination chosen by the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * will equal the requested {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} multiplied with the requested
- * {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR }. A limit can be set on the padding zoom if wanting
- * to control image quality further using {@link ExtensionCaptureRequest#EFV_MAX_PADDING_ZOOM_FACTOR }.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see CaptureRequest#CONTROL_ZOOM_RATIO
- * @see ExtensionCaptureRequest#EFV_MAX_PADDING_ZOOM_FACTOR
- * @see ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Boolean> EFV_AUTO_ZOOM = CaptureRequest.EFV_AUTO_ZOOM;
-
- /**
- * <p>Used to limit the {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } if
- * {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is enabled for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>If {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is enabled, this key can be used to set a limit
- * on the {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } chosen by the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode
- * to control image quality.</p>
- * <p><b>Range of valid values:</b><br>
- * The range of {@link CameraExtensionCharacteristics#EFV_PADDING_ZOOM_FACTOR_RANGE Range}. Use a value greater than or equal to
- * the {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } to
- * effectively utilize this key.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see ExtensionCaptureRequest#EFV_AUTO_ZOOM
- * @see ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR
- * @see CameraExtensionCharacteristics#EFV_PADDING_ZOOM_FACTOR_RANGE
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_MAX_PADDING_ZOOM_FACTOR = CaptureRequest.EFV_MAX_PADDING_ZOOM_FACTOR;
-
- /**
- * <p>Set the stabilization mode for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension</p>
- * <p>The desired stabilization mode. Gimbal stabilization mode provides simple, non-locked
- * video stabilization. Locked mode uses the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * stabilization feature to fixate on the current region, utilizing it as the target area for
- * stabilization.</p>
- * <p><b>Possible values:</b></p>
- * <ul>
- * <li>{@link #EFV_STABILIZATION_MODE_OFF OFF}</li>
- * <li>{@link #EFV_STABILIZATION_MODE_GIMBAL GIMBAL}</li>
- * <li>{@link #EFV_STABILIZATION_MODE_LOCKED LOCKED}</li>
- * </ul>
- *
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @see #EFV_STABILIZATION_MODE_OFF
- * @see #EFV_STABILIZATION_MODE_GIMBAL
- * @see #EFV_STABILIZATION_MODE_LOCKED
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Integer> EFV_STABILIZATION_MODE = CaptureRequest.EFV_STABILIZATION_MODE;
-
- /**
- * <p>Used to update the target region for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>A android.util.Pair<Integer,Integer> that represents the desired
- * <Horizontal,Vertical> shift of the current locked view (or target region) in
- * pixels. Negative values indicate left and upward shifts, while positive values indicate
- * right and downward shifts in the active array coordinate system.</p>
- * <p><b>Range of valid values:</b><br>
- * android.util.Pair<Integer,Integer> represents the
- * <Horizontal,Vertical> shift. The range for the horizontal shift is
- * [-max({@link ExtensionCaptureResult#EFV_PADDING_REGION }-left), max({@link ExtensionCaptureResult#EFV_PADDING_REGION }-right)].
- * The range for the vertical shift is
- * [-max({@link ExtensionCaptureResult#EFV_PADDING_REGION }-top), max({@link ExtensionCaptureResult#EFV_PADDING_REGION }-bottom)]</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see ExtensionCaptureResult#EFV_PADDING_REGION
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<android.util.Pair<Integer,Integer>> EFV_TRANSLATE_VIEWPORT = CaptureRequest.EFV_TRANSLATE_VIEWPORT;
-
- /**
- * <p>Representing the desired clockwise rotation
- * of the target region in degrees for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>Value representing the desired clockwise rotation of the target
- * region in degrees.</p>
- * <p><b>Range of valid values:</b><br>
- * 0 to 360</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_ROTATE_VIEWPORT = CaptureRequest.EFV_ROTATE_VIEWPORT;
-
-
- //
- // Enumeration values for CaptureRequest#EFV_STABILIZATION_MODE
- //
-
- /**
- * <p>No stabilization.</p>
- * @see ExtensionCaptureRequest#EFV_STABILIZATION_MODE
- */
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final int EFV_STABILIZATION_MODE_OFF = CaptureRequest.EFV_STABILIZATION_MODE_OFF;
-
- /**
- * <p>Gimbal stabilization mode.</p>
- * @see ExtensionCaptureRequest#EFV_STABILIZATION_MODE
- */
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final int EFV_STABILIZATION_MODE_GIMBAL = CaptureRequest.EFV_STABILIZATION_MODE_GIMBAL;
-
- /**
- * <p>Locked stabilization mode which uses the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * stabilization to directionally steady the target region.</p>
- * @see ExtensionCaptureRequest#EFV_STABILIZATION_MODE
- */
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final int EFV_STABILIZATION_MODE_LOCKED = CaptureRequest.EFV_STABILIZATION_MODE_LOCKED;
-
-}
diff --git a/core/java/android/hardware/camera2/ExtensionCaptureResult.java b/core/java/android/hardware/camera2/ExtensionCaptureResult.java
deleted file mode 100644
index b7ba78c..0000000
--- a/core/java/android/hardware/camera2/ExtensionCaptureResult.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-import android.hardware.camera2.CameraExtensionCharacteristics;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.CaptureResult.Key;
-import android.hardware.camera2.impl.ExtensionKey;
-import android.hardware.camera2.impl.PublicKey;
-
-import com.android.internal.camera.flags.Flags;
-
-/**
- * ExtensionCaptureResult contains definitions for extension-specific CaptureResult keys that
- * are available during a {@link android.hardware.camera2.CameraExtensionSession} after a
- * {@link android.hardware.camera2.CaptureRequest} is processed.
- *
- * Note that ExtensionCaptureResult is not intended to be used as a replacement
- * for CaptureResult in the extensions. It serves as a supplementary class providing
- * extension-specific CaptureResult keys. Developers should use these keys in conjunction
- * with regular CaptureResult objects during a
- * {@link android.hardware.camera2.CameraExtensionSession}.
- *
- * @see CaptureResult
- * @see CaptureRequest
- * @see CameraExtensionSession
- */
-@FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
-public final class ExtensionCaptureResult {
-
- /** To avoid exposing constructor */
- private ExtensionCaptureResult() {}
-
- /**
- * <p>The padding region for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>An array [left, top, right, bottom] of the padding in pixels remaining on all four sides
- * before the target region starts to go out of bounds.</p>
- * <p>The padding region denotes the area surrounding the stabilized target region within which
- * the camera can be moved while maintaining the target region in view. As the camera moves,
- * the padding region adjusts to represent the proximity of the target region to the
- * boundary, which is the point at which the target region will start to go out of bounds.</p>
- * <p><b>Range of valid values:</b><br>
- * The padding is the number of remaining pixels of padding in each direction.
- * The pixels reference the active array coordinate system. Negative values indicate the target region
- * is out of bounds. The value for this key may be null for when the stabilization mode is
- * in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_OFF }
- * or {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_GIMBAL } mode.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<int[]> EFV_PADDING_REGION = CaptureResult.EFV_PADDING_REGION;
-
- /**
- * <p>The padding region when {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is enabled for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>An array [left, top, right, bottom] of the padding in pixels remaining on all four sides
- * before the target region starts to go out of bounds.</p>
- * <p>This may differ from {@link ExtensionCaptureResult#EFV_PADDING_REGION } as the field of view can change
- * during {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM }, altering the boundary region and thus updating the padding between the
- * target region and the boundary.</p>
- * <p><b>Range of valid values:</b><br>
- * The padding is the number of remaining pixels of padding in each direction
- * when {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is enabled. Negative values indicate the target region is out of bounds.
- * The value for this key may be null for when the {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is not enabled.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see ExtensionCaptureRequest#EFV_AUTO_ZOOM
- * @see ExtensionCaptureResult#EFV_PADDING_REGION
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<int[]> EFV_AUTO_ZOOM_PADDING_REGION = CaptureResult.EFV_AUTO_ZOOM_PADDING_REGION;
-
- /**
- * <p>List of coordinates representing the target region relative to the
- * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE }
- * for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in
- * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>A list of android.graphics.PointF that define the coordinates of the target region
- * relative to the
- * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE }.
- * The array represents the target region coordinates as: top-left, top-right, bottom-left,
- * bottom-right.</p>
- * <p><b>Range of valid values:</b><br>
- * The list of target coordinates will define a region within the bounds of the
- * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE }</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<android.graphics.PointF[]> EFV_TARGET_COORDINATES = CaptureResult.EFV_TARGET_COORDINATES;
-
- /**
- * <p>Used to apply an additional digital zoom factor for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>For the {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * feature, an additional zoom factor is applied on top of the existing {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}.
- * This additional zoom factor serves as a buffer to provide more flexibility for the
- * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED }
- * mode. If {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } is not set, the default will be used.
- * The effectiveness of the stabilization may be influenced by the amount of padding zoom
- * applied. A higher padding zoom factor can stabilize the target region more effectively
- * with greater flexibility but may potentially impact image quality. Conversely, a lower
- * padding zoom factor may be used to prioritize preserving image quality, albeit with less
- * leeway in stabilizing the target region. It is recommended to set the
- * {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } to at least 1.5.</p>
- * <p>If {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is enabled, the requested {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } will be overridden.
- * {@link ExtensionCaptureRequest#EFV_MAX_PADDING_ZOOM_FACTOR } can be checked for more details on controlling the
- * padding zoom factor during {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM }.</p>
- * <p><b>Range of valid values:</b><br>
- * {@link CameraExtensionCharacteristics#EFV_PADDING_ZOOM_FACTOR_RANGE }</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see CaptureRequest#CONTROL_ZOOM_RATIO
- * @see ExtensionCaptureRequest#EFV_AUTO_ZOOM
- * @see ExtensionCaptureRequest#EFV_MAX_PADDING_ZOOM_FACTOR
- * @see ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR
- * @see CameraExtensionCharacteristics#EFV_PADDING_ZOOM_FACTOR_RANGE
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_PADDING_ZOOM_FACTOR = CaptureResult.EFV_PADDING_ZOOM_FACTOR;
-
- /**
- * <p>Set the stabilization mode for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension</p>
- * <p>The desired stabilization mode. Gimbal stabilization mode provides simple, non-locked
- * video stabilization. Locked mode uses the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * stabilization feature to fixate on the current region, utilizing it as the target area for
- * stabilization.</p>
- * <p><b>Possible values:</b></p>
- * <ul>
- * <li>{@link #EFV_STABILIZATION_MODE_OFF OFF}</li>
- * <li>{@link #EFV_STABILIZATION_MODE_GIMBAL GIMBAL}</li>
- * <li>{@link #EFV_STABILIZATION_MODE_LOCKED LOCKED}</li>
- * </ul>
- *
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- * @see #EFV_STABILIZATION_MODE_OFF
- * @see #EFV_STABILIZATION_MODE_GIMBAL
- * @see #EFV_STABILIZATION_MODE_LOCKED
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Integer> EFV_STABILIZATION_MODE = CaptureResult.EFV_STABILIZATION_MODE;
-
- /**
- * <p>Used to enable or disable auto zoom for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>Turn on auto zoom to let the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * feature decide at any given point a combination of
- * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} and {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR }
- * to keep the target region in view and stabilized. The combination chosen by the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * will equal the requested {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} multiplied with the requested
- * {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR }. A limit can be set on the padding zoom if wanting
- * to control image quality further using {@link ExtensionCaptureRequest#EFV_MAX_PADDING_ZOOM_FACTOR }.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see CaptureRequest#CONTROL_ZOOM_RATIO
- * @see ExtensionCaptureRequest#EFV_MAX_PADDING_ZOOM_FACTOR
- * @see ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Boolean> EFV_AUTO_ZOOM = CaptureResult.EFV_AUTO_ZOOM;
-
- /**
- * <p>Representing the desired clockwise rotation
- * of the target region in degrees for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>Value representing the desired clockwise rotation of the target
- * region in degrees.</p>
- * <p><b>Range of valid values:</b><br>
- * 0 to 360</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_ROTATE_VIEWPORT = CaptureResult.EFV_ROTATE_VIEWPORT;
-
- /**
- * <p>Used to update the target region for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>A android.util.Pair<Integer,Integer> that represents the desired
- * <Horizontal,Vertical> shift of the current locked view (or target region) in
- * pixels. Negative values indicate left and upward shifts, while positive values indicate
- * right and downward shifts in the active array coordinate system.</p>
- * <p><b>Range of valid values:</b><br>
- * android.util.Pair<Integer,Integer> represents the
- * <Horizontal,Vertical> shift. The range for the horizontal shift is
- * [-max({@link ExtensionCaptureResult#EFV_PADDING_REGION }-left), max({@link ExtensionCaptureResult#EFV_PADDING_REGION }-right)].
- * The range for the vertical shift is
- * [-max({@link ExtensionCaptureResult#EFV_PADDING_REGION }-top), max({@link ExtensionCaptureResult#EFV_PADDING_REGION }-bottom)]</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see ExtensionCaptureResult#EFV_PADDING_REGION
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<android.util.Pair<Integer,Integer>> EFV_TRANSLATE_VIEWPORT = CaptureResult.EFV_TRANSLATE_VIEWPORT;
-
- /**
- * <p>Used to limit the {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } if
- * {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is enabled for the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode.</p>
- * <p>If {@link ExtensionCaptureRequest#EFV_AUTO_ZOOM } is enabled, this key can be used to set a limit
- * on the {@link ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } chosen by the
- * {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
- * extension in {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED } mode
- * to control image quality.</p>
- * <p><b>Range of valid values:</b><br>
- * The range of {@link CameraExtensionCharacteristics#EFV_PADDING_ZOOM_FACTOR_RANGE }. Use a value greater than or equal to
- * the {@link android.hardware.camera2.ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR } to
- * effectively utilize this key.</p>
- * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
- *
- * @see ExtensionCaptureRequest#EFV_AUTO_ZOOM
- * @see ExtensionCaptureRequest#EFV_PADDING_ZOOM_FACTOR
- * @see CameraExtensionCharacteristics#EFV_PADDING_ZOOM_FACTOR_RANGE
- */
- @PublicKey
- @NonNull
- @ExtensionKey
- @FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
- public static final Key<Float> EFV_MAX_PADDING_ZOOM_FACTOR = CaptureResult.EFV_MAX_PADDING_ZOOM_FACTOR;
-
-}
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
index 001b794..32139b8 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
+++ b/core/java/android/hardware/camera2/extension/CameraOutputSurface.java
@@ -107,7 +107,6 @@
* {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
* unless specified by CameraOutputSurface.setDynamicRangeProfile.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public @DynamicRangeProfiles.Profile long getDynamicRangeProfile() {
return mOutputSurface.dynamicRangeProfile;
}
@@ -118,7 +117,6 @@
* unless specified by CameraOutputSurface.setColorSpace.
*/
@SuppressLint("MethodNameUnits")
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public int getColorSpace() {
return mOutputSurface.colorSpace;
}
@@ -128,7 +126,6 @@
* will be {@link android.hardware.camera2.params.DynamicRangeProfiles.STANDARD}
* unless explicitly set using this method.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setDynamicRangeProfile(
@DynamicRangeProfiles.Profile long dynamicRangeProfile) {
mOutputSurface.dynamicRangeProfile = dynamicRangeProfile;
diff --git a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
index 84b7a7f..32de1ce 100644
--- a/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
+++ b/core/java/android/hardware/camera2/extension/ExtensionConfiguration.java
@@ -83,7 +83,6 @@
* The default will be -1, indicating an unspecified ColorSpace,
* unless explicitly set using this method.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setColorSpace(int colorSpace) {
mColorSpace = colorSpace;
}
@@ -98,11 +97,7 @@
ret.sessionTemplateId = mSessionTemplateId;
ret.sessionType = mSessionType;
ret.outputConfigs = new ArrayList<>(mOutputs.size());
- if (Flags.extension10Bit()) {
- ret.colorSpace = mColorSpace;
- } else {
- ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
- }
+ ret.colorSpace = mColorSpace;
for (ExtensionOutputConfiguration outputConfig : mOutputs) {
ret.outputConfigs.add(outputConfig.getOutputConfig());
}
diff --git a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
index 3a67d61..8a47430 100644
--- a/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
+++ b/core/java/android/hardware/camera2/extension/ExtensionOutputConfiguration.java
@@ -80,11 +80,7 @@
config.outputId = new OutputConfigId();
config.outputId.id = mOutputConfigId;
config.surfaceGroupId = mSurfaceGroupId;
- if (Flags.extension10Bit()) {
- config.dynamicRangeProfile = surface.getDynamicRangeProfile();
- } else {
- config.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
- }
+ config.dynamicRangeProfile = surface.getDynamicRangeProfile();
}
@Nullable CameraOutputConfig getOutputConfig() {
diff --git a/core/java/android/hardware/camera2/extension/SessionProcessor.java b/core/java/android/hardware/camera2/extension/SessionProcessor.java
index 0ec5c0a..eead4ef 100644
--- a/core/java/android/hardware/camera2/extension/SessionProcessor.java
+++ b/core/java/android/hardware/camera2/extension/SessionProcessor.java
@@ -372,11 +372,9 @@
Map<String, CameraMetadataNative> charsMap, OutputSurface previewSurface,
OutputSurface imageCaptureSurface, OutputSurface postviewSurface)
throws RemoteException {
- if (Flags.surfaceLeakFix()) {
- mPreviewSurface = previewSurface;
- mPostviewSurface = postviewSurface;
- mImageCaptureSurface = imageCaptureSurface;
- }
+ mPreviewSurface = previewSurface;
+ mPostviewSurface = postviewSurface;
+ mImageCaptureSurface = imageCaptureSurface;
ExtensionConfiguration config = SessionProcessor.this.initSession(token, cameraId,
new CharacteristicsMap(charsMap),
new CameraOutputSurface(previewSurface),
@@ -399,16 +397,14 @@
@Override
public void deInitSession(IBinder token) throws RemoteException {
SessionProcessor.this.deInitSession(token);
- if (Flags.surfaceLeakFix()) {
- if ((mPreviewSurface != null) && (mPreviewSurface.surface != null)) {
- mPreviewSurface.surface.release();
- }
- if ((mImageCaptureSurface != null) && (mImageCaptureSurface.surface != null)) {
- mImageCaptureSurface.surface.release();
- }
- if ((mPostviewSurface != null) && (mPostviewSurface.surface != null)) {
- mPostviewSurface.surface.release();
- }
+ if ((mPreviewSurface != null) && (mPreviewSurface.surface != null)) {
+ mPreviewSurface.surface.release();
+ }
+ if ((mImageCaptureSurface != null) && (mImageCaptureSurface.surface != null)) {
+ mImageCaptureSurface.surface.release();
+ }
+ if ((mPostviewSurface != null) && (mPostviewSurface.surface != null)) {
+ mPostviewSurface.surface.release();
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 2e1e90c..323712d 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -148,7 +148,7 @@
for (OutputConfiguration c : config.getOutputConfigurations()) {
if (c.getDynamicRangeProfile() != DynamicRangeProfiles.STANDARD) {
- if (Flags.extension10Bit() && Flags.cameraExtensionsCharacteristicsGet()) {
+ if (Flags.cameraExtensionsCharacteristicsGet()) {
DynamicRangeProfiles dynamicProfiles = extensionChars.get(
config.getExtension(),
CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES);
@@ -190,9 +190,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (int format : supportedCaptureOutputFormats.toArray()) {
List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
config.getExtension(), format);
@@ -359,22 +357,20 @@
cameraOutput.setTimestampBase(OutputConfiguration.TIMESTAMP_BASE_SENSOR);
cameraOutput.setReadoutTimestampEnabled(false);
cameraOutput.setPhysicalCameraId(output.physicalCameraId);
- if (Flags.extension10Bit()) {
- boolean validDynamicRangeProfile = false;
- for (long profile = DynamicRangeProfiles.STANDARD;
- profile < DynamicRangeProfiles.PUBLIC_MAX; profile <<= 1) {
- if (output.dynamicRangeProfile == profile) {
- validDynamicRangeProfile = true;
- break;
- }
+ boolean validDynamicRangeProfile = false;
+ for (long profile = DynamicRangeProfiles.STANDARD;
+ profile < DynamicRangeProfiles.PUBLIC_MAX; profile <<= 1) {
+ if (output.dynamicRangeProfile == profile) {
+ validDynamicRangeProfile = true;
+ break;
}
- if (validDynamicRangeProfile) {
- cameraOutput.setDynamicRangeProfile(output.dynamicRangeProfile);
- } else {
- Log.e(TAG, "Extension configured dynamic range profile "
- + output.dynamicRangeProfile
- + " is not valid, using default DynamicRangeProfile.STANDARD");
- }
+ }
+ if (validDynamicRangeProfile) {
+ cameraOutput.setDynamicRangeProfile(output.dynamicRangeProfile);
+ } else {
+ Log.e(TAG, "Extension configured dynamic range profile "
+ + output.dynamicRangeProfile
+ + " is not valid, using default DynamicRangeProfile.STANDARD");
}
outputList.add(cameraOutput);
mCameraConfigMap.put(cameraOutput.getSurface(), output);
@@ -390,15 +386,13 @@
SessionConfiguration sessionConfiguration = new SessionConfiguration(sessionType,
outputList, new CameraExtensionUtils.HandlerExecutor(mHandler),
new SessionStateHandler());
- if (Flags.extension10Bit()) {
- if (sessionConfig.colorSpace >= 0
- && sessionConfig.colorSpace < ColorSpace.Named.values().length) {
- sessionConfiguration.setColorSpace(
- ColorSpace.Named.values()[sessionConfig.colorSpace]);
- } else {
- Log.e(TAG, "Extension configured color space " + sessionConfig.colorSpace
- + " is not valid, using default unspecified color space");
- }
+ if (sessionConfig.colorSpace >= 0
+ && sessionConfig.colorSpace < ColorSpace.Named.values().length) {
+ sessionConfiguration.setColorSpace(
+ ColorSpace.Named.values()[sessionConfig.colorSpace]);
+ } else {
+ Log.e(TAG, "Extension configured color space " + sessionConfig.colorSpace
+ + " is not valid, using default unspecified color space");
}
if ((sessionConfig.sessionParameter != null) &&
(!sessionConfig.sessionParameter.isEmpty())) {
@@ -459,16 +453,11 @@
ret.size.height = surfaceSize.getHeight();
ret.imageFormat = SurfaceUtils.getSurfaceFormat(s);
- if (Flags.extension10Bit()) {
- ret.dynamicRangeProfile = o.getDynamicRangeProfile();
- ColorSpace colorSpace = o.getColorSpace();
- if (colorSpace != null) {
- ret.colorSpace = colorSpace.getId();
- } else {
- ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
- }
+ ret.dynamicRangeProfile = o.getDynamicRangeProfile();
+ ColorSpace colorSpace = o.getColorSpace();
+ if (colorSpace != null) {
+ ret.colorSpace = colorSpace.getId();
} else {
- ret.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
}
} else {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
index 4ddf602..b5fb050 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
@@ -205,10 +205,6 @@
*/
@SuppressWarnings("AndroidFrameworkCompatChange")
public static boolean isCameraDeviceSetupSupported(CameraCharacteristics chars) {
- if (!Flags.featureCombinationQuery()) {
- return false;
- }
-
Integer queryVersion = chars.get(
CameraCharacteristics.INFO_SESSION_CONFIGURATION_QUERY_VERSION);
return queryVersion != null && queryVersion > Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
index a10e250..ab4ff72 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -208,10 +208,6 @@
}
public void onOutputSurface(Surface surface, int format) throws RemoteException {
- if (!Flags.extension10Bit() && format != ImageFormat.JPEG) {
- Log.e(TAG, "Unsupported output format: " + format);
- return;
- }
CameraExtensionUtils.SurfaceInfo surfaceInfo = CameraExtensionUtils.querySurface(surface);
mCaptureFormat = surfaceInfo.mFormat;
mOutputSurface = surface;
@@ -221,10 +217,6 @@
public void onPostviewOutputSurface(Surface surface) throws RemoteException {
CameraExtensionUtils.SurfaceInfo postviewSurfaceInfo =
CameraExtensionUtils.querySurface(surface);
- if (!Flags.extension10Bit() && postviewSurfaceInfo.mFormat != ImageFormat.JPEG) {
- Log.e(TAG, "Unsupported output format: " + postviewSurfaceInfo.mFormat);
- return;
- }
mPostviewFormat = postviewSurfaceInfo.mFormat;
mPostviewOutputSurface = surface;
initializePostviewPipeline();
@@ -240,10 +232,6 @@
}
public void onImageFormatUpdate(int format) throws RemoteException {
- if (!Flags.extension10Bit() && format != ImageFormat.YUV_420_888) {
- Log.e(TAG, "Unsupported input format: " + format);
- return;
- }
mFormat = format;
initializePipeline();
}
@@ -251,7 +239,7 @@
private void initializePipeline() throws RemoteException {
if ((mFormat != -1) && (mOutputSurface != null) && (mResolution != null) &&
(mYuvReader == null)) {
- if (Flags.extension10Bit() && mCaptureFormat == ImageFormat.YUV_420_888) {
+ if (mCaptureFormat == ImageFormat.YUV_420_888) {
// For the case when postview is JPEG and capture is YUV
mProcessor.onOutputSurface(mOutputSurface, mCaptureFormat);
} else {
@@ -274,7 +262,7 @@
private void initializePostviewPipeline() throws RemoteException {
if ((mFormat != -1) && (mPostviewOutputSurface != null) && (mPostviewResolution != null)
&& (mPostviewYuvReader == null)) {
- if (Flags.extension10Bit() && mPostviewFormat == ImageFormat.YUV_420_888) {
+ if (mPostviewFormat == ImageFormat.YUV_420_888) {
// For the case when postview is YUV and capture is JPEG
mProcessor.onPostviewOutputSurface(mPostviewOutputSurface);
} else {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index a4ae398..ce1609d 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -190,9 +190,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (int format : supportedCaptureOutputFormats.toArray()) {
List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
config.getExtension(), format);
@@ -401,7 +399,7 @@
if (surfaceInfo.mFormat == ImageFormat.JPEG) {
mImageJpegProcessor = new CameraExtensionJpegProcessor(mImageProcessor);
mImageProcessor = mImageJpegProcessor;
- } else if (Flags.extension10Bit() && mClientPostviewSurface != null) {
+ } else if (mClientPostviewSurface != null) {
// Handles case when postview is JPEG and capture is YUV
CameraExtensionUtils.SurfaceInfo postviewSurfaceInfo =
CameraExtensionUtils.querySurface(mClientPostviewSurface);
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index 40f0477..f91d277 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -113,32 +113,13 @@
SurfaceInfo surfaceInfo = querySurface(outputConfig.getSurface());
- if (Flags.extension10Bit()) {
- Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
- if (supportedPostviewSizes.get(surfaceInfo.mFormat)
- .contains(postviewSize)) {
- return outputConfig.getSurface();
- } else {
- throw new IllegalArgumentException("Postview size not supported!");
- }
+ Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
+ if (supportedPostviewSizes.get(surfaceInfo.mFormat)
+ .contains(postviewSize)) {
+ return outputConfig.getSurface();
} else {
- if (surfaceInfo.mFormat == captureFormat) {
- if (supportedPostviewSizes.containsKey(captureFormat)) {
- Size postviewSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
- if (supportedPostviewSizes.get(surfaceInfo.mFormat)
- .contains(postviewSize)) {
- return outputConfig.getSurface();
- } else {
- throw new IllegalArgumentException("Postview size not supported!");
- }
- }
- } else {
- throw new IllegalArgumentException("Postview format should be equivalent to "
- + " the capture format!");
- }
+ throw new IllegalArgumentException("Postview size not supported!");
}
-
- return null;
}
public static Surface getBurstCaptureSurface(
@@ -148,9 +129,7 @@
new IntArray(CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS.length);
supportedCaptureOutputFormats.addAll(
CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS);
- if (Flags.extension10Bit()) {
- supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
- }
+ supportedCaptureOutputFormats.add(ImageFormat.YCBCR_P010);
for (OutputConfiguration config : outputConfigs) {
SurfaceInfo surfaceInfo = querySurface(config.getSurface());
for (int supportedFormat : supportedCaptureOutputFormats.toArray()) {
diff --git a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
index bf3f59f..73f4ff4 100644
--- a/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/ExtensionSessionConfiguration.java
@@ -136,7 +136,6 @@
* or the color space implied by the dataSpace passed into an {@link ImageReader}'s
* constructor.</p>
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void setColorSpace(@NonNull ColorSpace.Named colorSpace) {
mColorSpace = colorSpace.ordinal();
for (OutputConfiguration outputConfiguration : mOutputs) {
@@ -150,7 +149,6 @@
/**
* Clear the color space, such that the default color space will be used.
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
public void clearColorSpace() {
mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
for (OutputConfiguration outputConfiguration : mOutputs) {
@@ -167,7 +165,6 @@
* @return the currently set color space, or null
* if not set
*/
- @FlaggedApi(Flags.FLAG_EXTENSION_10_BIT)
@SuppressLint("MethodNameUnits")
public @Nullable ColorSpace getColorSpace() {
if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 9bd4860..50c6b5b 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -165,12 +165,10 @@
source.readTypedList(outConfigs, OutputConfiguration.CREATOR);
// Ignore the values for hasSessionParameters and settings because we cannot reconstruct
// the CaptureRequest object.
- if (Flags.featureCombinationQuery()) {
- boolean hasSessionParameters = source.readBoolean();
- if (hasSessionParameters) {
- CameraMetadataNative settings = new CameraMetadataNative();
- settings.readFromParcel(source);
- }
+ boolean hasSessionParameters = source.readBoolean();
+ if (hasSessionParameters) {
+ CameraMetadataNative settings = new CameraMetadataNative();
+ settings.readFromParcel(source);
}
if ((inputWidth > 0) && (inputHeight > 0) && (inputFormat != -1)) {
@@ -212,14 +210,12 @@
dest.writeBoolean(/*isMultiResolution*/ false);
}
dest.writeTypedList(mOutputConfigurations);
- if (Flags.featureCombinationQuery()) {
- if (mSessionParameters != null) {
- dest.writeBoolean(/*hasSessionParameters*/true);
- CameraMetadataNative metadata = mSessionParameters.getNativeCopy();
- metadata.writeToParcel(dest, /*flags*/0);
- } else {
- dest.writeBoolean(/*hasSessionParameters*/false);
- }
+ if (mSessionParameters != null) {
+ dest.writeBoolean(/*hasSessionParameters*/true);
+ CameraMetadataNative metadata = mSessionParameters.getNativeCopy();
+ metadata.writeToParcel(dest, /*flags*/0);
+ } else {
+ dest.writeBoolean(/*hasSessionParameters*/false);
}
}
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index c7ebc63..0cabc4c 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -65,31 +65,34 @@
public static final int KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS = 23;
public static final int KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK = 24;
public static final int KEY_GESTURE_TYPE_SYSTEM_MUTE = 25;
- public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION = 26;
- public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS = 27;
- public static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT = 28;
- public static final int KEY_GESTURE_TYPE_LOCK_SCREEN = 29;
- public static final int KEY_GESTURE_TYPE_OPEN_NOTES = 30;
- public static final int KEY_GESTURE_TYPE_TOGGLE_POWER = 31;
- public static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION = 32;
- public static final int KEY_GESTURE_TYPE_SLEEP = 33;
- public static final int KEY_GESTURE_TYPE_WAKEUP = 34;
- public static final int KEY_GESTURE_TYPE_MEDIA_KEY = 35;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER = 36;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL = 37;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS = 38;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR = 39;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR = 40;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC = 41;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS = 42;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING = 43;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY = 44;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES = 45;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER = 46;
- public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS = 47;
- public static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME = 48;
- public static final int KEY_GESTURE_TYPE_DESKTOP_MODE = 49;
- public static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION = 50;
+ public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT = 26;
+ public static final int KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT = 27;
+ public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT = 28;
+ public static final int KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT = 29;
+ public static final int KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT = 30;
+ public static final int KEY_GESTURE_TYPE_LOCK_SCREEN = 31;
+ public static final int KEY_GESTURE_TYPE_OPEN_NOTES = 32;
+ public static final int KEY_GESTURE_TYPE_TOGGLE_POWER = 33;
+ public static final int KEY_GESTURE_TYPE_SYSTEM_NAVIGATION = 34;
+ public static final int KEY_GESTURE_TYPE_SLEEP = 35;
+ public static final int KEY_GESTURE_TYPE_WAKEUP = 36;
+ public static final int KEY_GESTURE_TYPE_MEDIA_KEY = 37;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER = 38;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL = 39;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS = 40;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR = 41;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR = 42;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC = 43;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS = 44;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING = 45;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_GALLERY = 46;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FILES = 47;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_WEATHER = 48;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_DEFAULT_FITNESS = 49;
+ public static final int KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME = 50;
+ public static final int KEY_GESTURE_TYPE_DESKTOP_MODE = 51;
+ public static final int KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION = 52;
+ public static final int KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER = 53;
public static final int FLAG_CANCELLED = 1;
@@ -130,8 +133,10 @@
KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
KEY_GESTURE_TYPE_SYSTEM_MUTE,
- KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION,
- KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT,
+ KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT,
+ KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT,
KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
KEY_GESTURE_TYPE_LOCK_SCREEN,
KEY_GESTURE_TYPE_OPEN_NOTES,
@@ -155,6 +160,7 @@
KEY_GESTURE_TYPE_LAUNCH_APPLICATION_BY_PACKAGE_NAME,
KEY_GESTURE_TYPE_DESKTOP_MODE,
KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION,
+ KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER
})
@Retention(RetentionPolicy.SOURCE)
public @interface KeyGestureType {
@@ -331,6 +337,7 @@
case KEY_GESTURE_TYPE_HOME:
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME;
case KEY_GESTURE_TYPE_RECENT_APPS:
+ case KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER:
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS;
case KEY_GESTURE_TYPE_BACK:
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK;
@@ -378,9 +385,11 @@
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_CAPS_LOCK;
case KEY_GESTURE_TYPE_SYSTEM_MUTE:
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE;
- case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION:
+ case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT:
+ case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT:
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SPLIT_SCREEN_NAVIGATION;
- case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS:
+ case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT:
+ case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT:
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__CHANGE_SPLITSCREEN_FOCUS;
case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TRIGGER_BUG_REPORT;
@@ -487,10 +496,14 @@
return "KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK";
case KEY_GESTURE_TYPE_SYSTEM_MUTE:
return "KEY_GESTURE_TYPE_SYSTEM_MUTE";
- case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION:
- return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION";
- case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS:
- return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS";
+ case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT:
+ return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT";
+ case KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT:
+ return "KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT";
+ case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT:
+ return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT";
+ case KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT:
+ return "KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT";
case KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
return "KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT";
case KEY_GESTURE_TYPE_LOCK_SCREEN:
@@ -537,6 +550,8 @@
return "KEY_GESTURE_TYPE_DESKTOP_MODE";
case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
return "KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION";
+ case KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER:
+ return "KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER";
default:
return Integer.toHexString(value);
}
diff --git a/core/java/android/hardware/input/VirtualInputDeviceConfig.java b/core/java/android/hardware/input/VirtualInputDeviceConfig.java
index a87980c..e8ef8cd 100644
--- a/core/java/android/hardware/input/VirtualInputDeviceConfig.java
+++ b/core/java/android/hardware/input/VirtualInputDeviceConfig.java
@@ -57,7 +57,7 @@
mVendorId = builder.mVendorId;
mProductId = builder.mProductId;
mAssociatedDisplayId = builder.mAssociatedDisplayId;
- mInputDeviceName = Objects.requireNonNull(builder.mInputDeviceName);
+ mInputDeviceName = Objects.requireNonNull(builder.mInputDeviceName, "Missing device name");
if (mAssociatedDisplayId == Display.INVALID_DISPLAY) {
throw new IllegalArgumentException(
@@ -77,7 +77,7 @@
mVendorId = in.readInt();
mProductId = in.readInt();
mAssociatedDisplayId = in.readInt();
- mInputDeviceName = Objects.requireNonNull(in.readString8());
+ mInputDeviceName = Objects.requireNonNull(in.readString8(), "Missing device name");
}
/**
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 4478592..983bbc3 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -112,6 +112,20 @@
}
flag {
+ namespace: "input_native"
+ name: "use_key_gesture_event_handler"
+ description: "Use KeyGestureEvent handler APIs to control system shortcuts and key gestures"
+ bug: "358569822"
+}
+
+flag {
+ namespace: "input_native"
+ name: "use_key_gesture_event_handler_multi_press_gestures"
+ description: "Use KeyGestureEvent handler APIs to control multi key press gestures"
+ bug: "358569822"
+}
+
+flag {
name: "keyboard_repeat_keys"
namespace: "input_native"
description: "Allow configurable timeout before key repeat and repeat delay rate for key repeats"
diff --git a/core/java/android/net/TEST_MAPPING b/core/java/android/net/TEST_MAPPING
index 3df5616..ea509bb 100644
--- a/core/java/android/net/TEST_MAPPING
+++ b/core/java/android/net/TEST_MAPPING
@@ -19,21 +19,7 @@
],
"presubmit": [
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.net"
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksCoreTests_android_net"
}
]
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c4d12d4..996a288 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2066,9 +2066,11 @@
public static final int EVENT_LONG_WAKE_LOCK = 0x0014;
// Event for reporting change of some device states, triggered by a specific UID
public static final int EVENT_STATE_CHANGE = 0x0015;
+ // Event for reporting change of screen states.
+ public static final int EVENT_DISPLAY_STATE_CHANGED = 0x0016;
// Number of event types.
- public static final int EVENT_COUNT = 0x0016;
+ public static final int EVENT_COUNT = 0x0017;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -3079,13 +3081,14 @@
public static final String[] HISTORY_EVENT_NAMES = new String[] {
"null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
"active", "pkginst", "pkgunin", "alarm", "stats", "pkginactive", "pkgactive",
- "tmpwhitelist", "screenwake", "wakeupap", "longwake", "state"
+ "tmpwhitelist", "screenwake", "wakeupap", "longwake", "state",
+ "display_state_changed"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
"Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
"Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw",
- "Esw", "Ewa", "Elw", "Eec", "Esc"
+ "Esw", "Ewa", "Elw", "Eec", "Esc", "Eds"
};
@FunctionalInterface
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 2c7b9c0..89a5e5d 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -415,7 +415,7 @@
* Returns the base directory for per-user system directory, device encrypted.
* {@hide}
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SystemApi
@FlaggedApi(android.crashrecovery.flags.Flags.FLAG_ENABLE_CRASHRECOVERY)
public static @NonNull File getDataSystemDeDirectory() {
return buildPath(getDataDirectory(), "system_de");
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index bf44d65..0776cf4 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
@@ -551,7 +552,7 @@
}
/**
- * An interface suitable for a lambda expression instead of a QueryHandler.
+ * An interface suitable for a lambda expression instead of a QueryHandler applying remote call.
* @hide
*/
public interface RemoteCall<Query, Result> {
@@ -559,6 +560,14 @@
}
/**
+ * An interface suitable for a lambda expression instead of a QueryHandler bypassing the cache.
+ * @hide
+ */
+ public interface BypassCall<Query> {
+ Boolean apply(Query query);
+ }
+
+ /**
* This is a query handler that is created with a lambda expression that is invoked
* every time the handler is called. The handler is specifically meant for services
* hosted by system_server; the handler automatically rethrows RemoteException as a
@@ -580,11 +589,54 @@
}
}
+
/**
* Create a cache using a config and a lambda expression.
+ * @param config The configuration for the cache.
+ * @param remoteCall The lambda expression that will be invoked to fetch the data.
* @hide
*/
- public IpcDataCache(@NonNull Config config, @NonNull RemoteCall<Query, Result> computer) {
- this(config, new SystemServerCallHandler<>(computer));
+ public IpcDataCache(@NonNull Config config, @NonNull RemoteCall<Query, Result> remoteCall) {
+ this(config, android.multiuser.Flags.cachingDevelopmentImprovements() ?
+ new QueryHandler<Query, Result>() {
+ @Override
+ public Result apply(Query query) {
+ try {
+ return remoteCall.apply(query);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ } : new SystemServerCallHandler<>(remoteCall));
+ }
+
+
+ /**
+ * Create a cache using a config and a lambda expression.
+ * @param config The configuration for the cache.
+ * @param remoteCall The lambda expression that will be invoked to fetch the data.
+ * @param bypass The lambda expression that will be invoked to determine if the cache should be
+ * bypassed.
+ * @hide
+ */
+ @FlaggedApi(android.multiuser.Flags.FLAG_CACHING_DEVELOPMENT_IMPROVEMENTS)
+ public IpcDataCache(@NonNull Config config,
+ @NonNull RemoteCall<Query, Result> remoteCall,
+ @NonNull BypassCall<Query> bypass) {
+ this(config, new QueryHandler<Query, Result>() {
+ @Override
+ public Result apply(Query query) {
+ try {
+ return remoteCall.apply(query);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean shouldBypassCache(Query query) {
+ return bypass.apply(query);
+ }
+ });
}
}
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index 58ab5b6..cfbf528 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -138,11 +138,14 @@
Log.w(TAG, "Failed to vibrate; no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason=" + reason);
try {
mService.vibrate(uid, mContext.getDeviceId(), opPkg, effect, attributes, reason,
mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -152,11 +155,14 @@
Log.w(TAG, "Failed to perform haptic feedback; no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedback, reason=" + reason);
try {
mService.performHapticFeedback(mUid, mContext.getDeviceId(), mPackageName, constant,
reason, flags, privFlags);
} catch (RemoteException e) {
Log.w(TAG, "Failed to perform haptic feedback.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -168,11 +174,15 @@
+ " no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR,
+ "performHapticFeedbackForInputDevice, reason=" + reason);
try {
mService.performHapticFeedbackForInputDevice(mUid, mContext.getDeviceId(), mPackageName,
constant, inputDeviceId, inputSource, reason, flags, privFlags);
} catch (RemoteException e) {
Log.w(TAG, "Failed to perform haptic feedback for input device.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index 728db27..effe555 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -38,33 +38,15 @@
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "BugreportManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "BugreportManagerTestCases_android_server_os"
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "CtsBugreportTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsBugreportTestCases_android_server_os"
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "ShellTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ShellTests_android_server_os"
},
{
"file_patterns": [
@@ -99,12 +81,7 @@
"Parcel\\.java",
"[^/]*Bundle[^/]*\\.java"
],
- "name": "FrameworksMockingCoreTests",
- "options": [
- { "include-filter": "android.os.BundleRecyclingTest"},
- { "exclude-annotation": "androidx.test.filters.FlakyTest" },
- { "exclude-annotation": "org.junit.Ignore" }
- ]
+ "name": "FrameworksMockingCoreTests_os_bundlerecyclingtest"
},
{
"file_patterns": [
@@ -116,12 +93,7 @@
},
{
"file_patterns": ["SharedMemory[^/]*\\.java"],
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-filter": "android.os.cts.SharedMemoryTest"
- }
- ]
+ "name": "CtsOsTestCases_cts_sharedmemorytest"
},
{
"file_patterns": ["Environment[^/]*\\.java"],
diff --git a/core/java/android/permission/TEST_MAPPING b/core/java/android/permission/TEST_MAPPING
index b317b80..3e5a131 100644
--- a/core/java/android/permission/TEST_MAPPING
+++ b/core/java/android/permission/TEST_MAPPING
@@ -6,26 +6,10 @@
],
"postsubmit": [
{
- "name": "CtsVirtualDevicesAudioTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.virtualdevice.cts.audio.VirtualAudioPermissionTest"
- }
- ]
+ "name": "CtsVirtualDevicesAudioTestCases_audio_virtualaudiopermissiontest"
},
{
- "name": "CtsVirtualDevicesAppLaunchTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.virtualdevice.cts.applaunch.VirtualDevicePermissionTest"
- }
- ]
+ "name": "CtsVirtualDevicesAppLaunchTestCases_applaunch_virtualdevicepermissiontest"
}
]
}
diff --git a/core/java/android/print/TEST_MAPPING b/core/java/android/print/TEST_MAPPING
index 4fa8822..1033b1a 100644
--- a/core/java/android/print/TEST_MAPPING
+++ b/core/java/android/print/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPrintTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ]
+ "name": "CtsPrintTestCases_Presubmit"
}
]
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index f6eb4b5..a622810 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3018,170 +3018,180 @@
com.android.internal.R.string.config_rawContactsLocalAccountType));
}
+
+
/**
- * Represents the state of the default account, and the actual {@link Account} if it's
- * a cloud account.
- * If the default account is set to {@link #DEFAULT_ACCOUNT_STATE_LOCAL} or
- * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}, new raw contacts requested for insertion
- * without a
- * specified {@link Account} will be saved in the default account.
- * The default account can have one of the following four states:
- * <ul>
- * <li> {@link #DEFAULT_ACCOUNT_STATE_INVALID}: An invalid state that should not
- * occur on the device. </li>
- * <li> {@link #DEFAULT_ACCOUNT_STATE_NOT_SET}: The default account has not
- * been set by the user. </li>
- * <li> {@link #DEFAULT_ACCOUNT_STATE_LOCAL}: The default account is set to
- * the local device storage. New raw contacts requested for insertion without a
- * specified
- * {@link Account} will be saved in a null or custom local account. </li>
- * <li> {@link #DEFAULT_ACCOUNT_STATE_CLOUD}: The default account is set to a
- * cloud-synced account. New raw contacts requested for insertion without a specified
- * {@link Account} will be saved in {@link mCloudAccount}. </li>
- * </ul>
+ * Class containing utility methods around the default account.
+ * New raw contacts requested to be inserted without a specified {@link Account} will be
+ * saved in the default account.
*/
@FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
- public static final class DefaultAccountAndState {
- // The state of the default account.
- /** A state that is invalid. */
- public static final int DEFAULT_ACCOUNT_STATE_INVALID = 0;
-
- /** A state indicating that default account is not set. */
- public static final int DEFAULT_ACCOUNT_STATE_NOT_SET = 1;
-
- /** A state indicating that default account is set to local device storage. */
- public static final int DEFAULT_ACCOUNT_STATE_LOCAL = 2;
+ public static final class DefaultAccount {
/**
- * A state indicating that the default account is set as an account that is synced
- * to the cloud.
+ * Represents the state of the default account, and the actual {@link Account} if it's
+ * a cloud account.
+ * If the default account is set to {@link #DEFAULT_ACCOUNT_STATE_LOCAL} or
+ * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}, new raw contacts requested for insertion
+ * without a
+ * specified {@link Account} will be saved in the default account.
+ * The default account can have one of the following four states:
+ * <ul>
+ * <li> {@link #DEFAULT_ACCOUNT_STATE_NOT_SET}: The default account has not
+ * been set by the user. </li>
+ * <li> {@link #DEFAULT_ACCOUNT_STATE_LOCAL}: The default account is set to
+ * the local device storage. New raw contacts requested for insertion without a
+ * specified
+ * {@link Account} will be saved in a null or custom local account. </li>
+ * <li> {@link #DEFAULT_ACCOUNT_STATE_CLOUD}: The default account is set to a
+ * cloud-synced account. New raw contacts requested for insertion without a specified
+ * {@link Account} will be saved in the default cloud account. </li>
+ * </ul>
*/
- public static final int DEFAULT_ACCOUNT_STATE_CLOUD = 3;
+ @FlaggedApi(Flags.FLAG_NEW_DEFAULT_ACCOUNT_API_ENABLED)
+ public static final class DefaultAccountAndState {
+ /** A state indicating that default account is not set. */
+ public static final int DEFAULT_ACCOUNT_STATE_NOT_SET = 1;
- /**
- * The state of the default account. One of
- * {@link #DEFAULT_ACCOUNT_STATE_NOT_SET},
- * {@link #DEFAULT_ACCOUNT_STATE_LOCAL} or
- * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
- */
- @DefaultAccountState
- private final int mState;
+ /** A state indicating that default account is set to local device storage. */
+ public static final int DEFAULT_ACCOUNT_STATE_LOCAL = 2;
- /**
- * The account of the default account, when {@link mState} is {
- *
- * @link #STATE_SET_TO_CLOUD}, or null otherwise.
- */
- private final Account mCloudAccount;
+ /**
+ * A state indicating that the default account is set as an account that is synced
+ * to the cloud.
+ */
+ public static final int DEFAULT_ACCOUNT_STATE_CLOUD = 3;
- /**
- * Constructs a new `DefaultAccountAndState` instance with the specified state and
- * cloud
- * account.
- *
- * @param state The state of the default account.
- * @param cloudAccount The cloud account associated with the default account,
- * or null if the state is not
- * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
- */
- public DefaultAccountAndState(@DefaultAccountState int state,
- @Nullable Account cloudAccount) {
- if (state == DEFAULT_ACCOUNT_STATE_INVALID) {
- throw new IllegalArgumentException("Invalid default account state.");
- }
- if ((state == DEFAULT_ACCOUNT_STATE_CLOUD) != (cloudAccount != null)) {
- throw new IllegalArgumentException(
- "Default account can be set to cloud if and only if the cloud "
- + "account is provided.");
- }
- this.mState = state;
- this.mCloudAccount =
- (mState == DEFAULT_ACCOUNT_STATE_CLOUD) ? cloudAccount : null;
- }
+ /**
+ * The state of the default account. One of
+ * {@link #DEFAULT_ACCOUNT_STATE_NOT_SET},
+ * {@link #DEFAULT_ACCOUNT_STATE_LOCAL} or
+ * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
+ */
+ @DefaultAccountState
+ private final int mState;
- /**
- * Creates a `DefaultAccountAndState` instance representing a default account
- * that is set to the cloud and associated with the specified cloud account.
- *
- * @param cloudAccount The non-null cloud account associated with the default
- * contacts
- * account.
- * @return A new `DefaultAccountAndState` instance with state
- * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
- */
- public static @NonNull DefaultAccountAndState ofCloud(
- @NonNull Account cloudAccount) {
- return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_CLOUD, cloudAccount);
- }
+ /**
+ * The account of the default account, when {@link mState} is {
+ *
+ * @link #STATE_SET_TO_CLOUD}, or null otherwise.
+ */
+ private final Account mCloudAccount;
- /**
- * Creates a `DefaultAccountAndState` instance representing a default account
- * that is set to the local device storage.
- *
- * @return A new `DefaultAccountAndState` instance with state
- * {@link #DEFAULT_ACCOUNT_STATE_LOCAL}.
- */
- public static @NonNull DefaultAccountAndState ofLocal() {
- return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_LOCAL, null);
- }
-
- /**
- * Creates a `DefaultAccountAndState` instance representing a default account
- * that is not set.
- *
- * @return A new `DefaultAccountAndState` instance with state
- * {@link #DEFAULT_ACCOUNT_STATE_NOT_SET}.
- */
- public static @NonNull DefaultAccountAndState ofNotSet() {
- return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_NOT_SET, null);
- }
-
- /**
- * @return the state of the default account.
- */
- @DefaultAccountState
- public int getState() {
- return mState;
- }
-
- /**
- * @return the cloud account associated with the default account, or null if the
- * state is not {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
- */
- public @Nullable Account getCloudAccount() {
- return mCloudAccount;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mState, mCloudAccount);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof DefaultAccountAndState that)) {
- return false;
+ /**
+ * Constructs a new `DefaultAccountAndState` instance with the specified state and
+ * cloud
+ * account.
+ *
+ * @param state The state of the default account.
+ * @param cloudAccount The cloud account associated with the default account,
+ * or null if the state is not
+ * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
+ */
+ public DefaultAccountAndState(@DefaultAccountState int state,
+ @Nullable Account cloudAccount) {
+ if (!isValidDefaultAccountState(state)) {
+ throw new IllegalArgumentException("Invalid default account state.");
+ }
+ if ((state == DEFAULT_ACCOUNT_STATE_CLOUD) != (cloudAccount != null)) {
+ throw new IllegalArgumentException(
+ "Default account can be set to cloud if and only if the cloud "
+ + "account is provided.");
+ }
+ this.mState = state;
+ this.mCloudAccount =
+ (mState == DEFAULT_ACCOUNT_STATE_CLOUD) ? cloudAccount : null;
}
- return mState == that.mState && Objects.equals(mCloudAccount,
- that.mCloudAccount);
- }
+ /**
+ * Creates a `DefaultAccountAndState` instance representing a default account
+ * that is set to the cloud and associated with the specified cloud account.
+ *
+ * @param cloudAccount The non-null cloud account associated with the default
+ * contacts
+ * account.
+ * @return A new `DefaultAccountAndState` instance with state
+ * {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
+ */
+ public static @NonNull DefaultAccountAndState ofCloud(
+ @NonNull Account cloudAccount) {
+ return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_CLOUD, cloudAccount);
+ }
- /**
- * Annotation for all default account states.
- *
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = {"DEFAULT_ACCOUNT_STATE_"},
- value = {DEFAULT_ACCOUNT_STATE_INVALID,
- DEFAULT_ACCOUNT_STATE_NOT_SET,
- DEFAULT_ACCOUNT_STATE_LOCAL, DEFAULT_ACCOUNT_STATE_CLOUD})
- public @interface DefaultAccountState {
+ /**
+ * Creates a `DefaultAccountAndState` instance representing a default account
+ * that is set to the local device storage.
+ *
+ * @return A new `DefaultAccountAndState` instance with state
+ * {@link #DEFAULT_ACCOUNT_STATE_LOCAL}.
+ */
+ public static @NonNull DefaultAccountAndState ofLocal() {
+ return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_LOCAL, null);
+ }
+
+ /**
+ * Creates a `DefaultAccountAndState` instance representing a default account
+ * that is not set.
+ *
+ * @return A new `DefaultAccountAndState` instance with state
+ * {@link #DEFAULT_ACCOUNT_STATE_NOT_SET}.
+ */
+ public static @NonNull DefaultAccountAndState ofNotSet() {
+ return new DefaultAccountAndState(DEFAULT_ACCOUNT_STATE_NOT_SET, null);
+ }
+
+ /**
+ * @return the state of the default account.
+ */
+ @DefaultAccountState
+ public int getState() {
+ return mState;
+ }
+
+ /**
+ * @return the cloud account associated with the default account, or null if the
+ * state is not {@link #DEFAULT_ACCOUNT_STATE_CLOUD}.
+ */
+ public @Nullable Account getCloudAccount() {
+ return mCloudAccount;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mState, mCloudAccount);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof DefaultAccountAndState that)) {
+ return false;
+ }
+
+ return mState == that.mState && Objects.equals(mCloudAccount,
+ that.mCloudAccount);
+ }
+
+ private static boolean isValidDefaultAccountState(int state) {
+ return state == DEFAULT_ACCOUNT_STATE_NOT_SET
+ || state == DEFAULT_ACCOUNT_STATE_LOCAL
+ || state == DEFAULT_ACCOUNT_STATE_CLOUD;
+ }
+
+ /**
+ * Annotation for all default account states.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"DEFAULT_ACCOUNT_STATE_"},
+ value = {DEFAULT_ACCOUNT_STATE_NOT_SET,
+ DEFAULT_ACCOUNT_STATE_LOCAL, DEFAULT_ACCOUNT_STATE_CLOUD})
+ public @interface DefaultAccountState {
+ }
}
}
diff --git a/core/java/android/provider/TEST_MAPPING b/core/java/android/provider/TEST_MAPPING
index 2eb285d..a6fe301 100644
--- a/core/java/android/provider/TEST_MAPPING
+++ b/core/java/android/provider/TEST_MAPPING
@@ -24,12 +24,7 @@
"name": "SettingsProviderTest"
},
{
- "name": "CtsPackageManagerHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.ReadableSettingsFieldsTest"
- }
- ]
+ "name": "CtsPackageManagerHostTestCases_cts_readablesettingsfieldstest"
}
],
"postsubmit": [
diff --git a/core/java/android/security/TEST_MAPPING b/core/java/android/security/TEST_MAPPING
index 5a679b1..e1c7f3c 100644
--- a/core/java/android/security/TEST_MAPPING
+++ b/core/java/android/security/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsSecurityTestCases",
- "options": [
- {
- "include-filter": "android.security.cts.FileIntegrityManagerTest"
- }
- ],
+ "name": "CtsSecurityTestCases_cts_fileintegritymanagertest",
"file_patterns": [
"FileIntegrityManager\\.java",
"IFileIntegrityService\\.aidl"
diff --git a/core/java/android/security/attestationverification/AttestationVerificationManager.java b/core/java/android/security/attestationverification/AttestationVerificationManager.java
index 2e61db1..acf3382 100644
--- a/core/java/android/security/attestationverification/AttestationVerificationManager.java
+++ b/core/java/android/security/attestationverification/AttestationVerificationManager.java
@@ -322,6 +322,10 @@
/** Requirements bundle parameter for a challenge. */
public static final String PARAM_CHALLENGE = "localbinding.challenge";
+ /** Requirements bundle parameter for max patch level diff (int) for a peer device. **/
+ public static final String PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS =
+ "param_max_patch_level_diff_months";
+
/** @hide */
public static String localBindingTypeToString(@LocalBindingType int localBindingType) {
final String text;
diff --git a/core/java/android/security/attestationverification/OWNERS b/core/java/android/security/attestationverification/OWNERS
index 80a1f44..15b9ce4 100644
--- a/core/java/android/security/attestationverification/OWNERS
+++ b/core/java/android/security/attestationverification/OWNERS
@@ -2,3 +2,6 @@
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
\ No newline at end of file
diff --git a/core/java/android/service/notification/TEST_MAPPING b/core/java/android/service/notification/TEST_MAPPING
index 468c451..dc7129cd 100644
--- a/core/java/android/service/notification/TEST_MAPPING
+++ b/core/java/android/service/notification/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "CtsNotificationTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsNotificationTestCases_notification"
},
{
- "name": "FrameworksUiServicesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "FrameworksUiServicesTests_notification"
}
],
"postsubmit": [
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 3d8d933..d45b24e 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -313,6 +313,7 @@
private static final String RULE_ATT_DELETION_INSTANT = "deletionInstant";
private static final String RULE_ATT_DISABLED_ORIGIN = "disabledOrigin";
private static final String RULE_ATT_LEGACY_SUPPRESSED_EFFECTS = "legacySuppressedEffects";
+ private static final String RULE_ATT_CONDITION_OVERRIDE = "conditionOverride";
private static final String DEVICE_EFFECT_DISPLAY_GRAYSCALE = "zdeDisplayGrayscale";
private static final String DEVICE_EFFECT_SUPPRESS_AMBIENT_DISPLAY =
@@ -1045,6 +1046,8 @@
DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
} else if (MANUAL_TAG.equals(tag)) {
rt.manualRule = readRuleXml(parser);
+ // manualRule.enabled can never be false, but it was broken in some builds.
+ rt.manualRule.enabled = true;
// Manual rule may be present prior to modes_ui if it were on, but in that
// case it would not have a set policy, so make note of the need to set
// it up later.
@@ -1144,7 +1147,7 @@
if (manualRule != null) {
out.startTag(null, MANUAL_TAG);
- writeRuleXml(manualRule, out);
+ writeRuleXml(manualRule, out, forBackup);
out.endTag(null, MANUAL_TAG);
}
final int N = automaticRules.size();
@@ -1153,7 +1156,7 @@
final ZenRule automaticRule = automaticRules.valueAt(i);
out.startTag(null, AUTOMATIC_TAG);
out.attribute(null, RULE_ATT_ID, id);
- writeRuleXml(automaticRule, out);
+ writeRuleXml(automaticRule, out, forBackup);
out.endTag(null, AUTOMATIC_TAG);
}
if (Flags.modesApi() && !forBackup) {
@@ -1161,7 +1164,7 @@
final ZenRule deletedRule = deletedRules.valueAt(i);
out.startTag(null, AUTOMATIC_DELETED_TAG);
out.attribute(null, RULE_ATT_ID, deletedRule.id);
- writeRuleXml(deletedRule, out);
+ writeRuleXml(deletedRule, out, forBackup);
out.endTag(null, AUTOMATIC_DELETED_TAG);
}
}
@@ -1220,12 +1223,15 @@
ORIGIN_UNKNOWN);
rt.legacySuppressedEffects = safeInt(parser,
RULE_ATT_LEGACY_SUPPRESSED_EFFECTS, 0);
+ rt.conditionOverride = safeInt(parser, RULE_ATT_CONDITION_OVERRIDE,
+ ZenRule.OVERRIDE_NONE);
}
}
return rt;
}
- public static void writeRuleXml(ZenRule rule, TypedXmlSerializer out) throws IOException {
+ public static void writeRuleXml(ZenRule rule, TypedXmlSerializer out, boolean forBackup)
+ throws IOException {
out.attributeBoolean(null, RULE_ATT_ENABLED, rule.enabled);
if (rule.name != null) {
out.attribute(null, RULE_ATT_NAME, rule.name);
@@ -1279,6 +1285,9 @@
out.attributeInt(null, RULE_ATT_DISABLED_ORIGIN, rule.disabledOrigin);
out.attributeInt(null, RULE_ATT_LEGACY_SUPPRESSED_EFFECTS,
rule.legacySuppressedEffects);
+ if (rule.conditionOverride == ZenRule.OVERRIDE_ACTIVATE && !forBackup) {
+ out.attributeInt(null, RULE_ATT_CONDITION_OVERRIDE, rule.conditionOverride);
+ }
}
}
}
@@ -2553,7 +2562,7 @@
if (!Flags.modesUi()) {
return manualRule != null;
}
- return manualRule != null && manualRule.isAutomaticActive();
+ return manualRule != null && manualRule.isActive();
}
public static class ZenRule implements Parcelable {
@@ -2622,9 +2631,12 @@
int legacySuppressedEffects;
/**
* Signals a user's action to (temporarily or permanently) activate or deactivate this
- * rule, overruling the condition set by the owner. This value is not stored to disk, as
- * it shouldn't survive reboots or be involved in B&R. It might be reset by certain
- * owner-provided state transitions as well.
+ * rule, overruling the condition set by the owner.
+ *
+ * <p>An {@link #OVERRIDE_ACTIVATE} is stored to disk, since we want it to survive reboots
+ * (but it's not included in B&R), while an {@link #OVERRIDE_DEACTIVATE} is not (meaning
+ * that snoozed rules may reactivate on reboot). It might be reset by certain owner-provided
+ * state transitions as well.
*/
@FlaggedApi(Flags.FLAG_MODES_UI)
@ConditionOverride
@@ -2932,8 +2944,7 @@
}
}
- // TODO: b/363193376 - Rename to isActive()
- public boolean isAutomaticActive() {
+ public boolean isActive() {
if (Flags.modesApi() && Flags.modesUi()) {
if (!enabled || getPkg() == null) {
return false;
@@ -3173,7 +3184,7 @@
// DND turned on by an automatic rule
for (ZenRule automaticRule : config.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
if (isValidEventConditionId(automaticRule.conditionId)
|| isValidScheduleConditionId(automaticRule.conditionId)) {
// set text if automatic rule end time is the latest active rule end time
diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java
index 05c2a9c..60a7d6b 100644
--- a/core/java/android/service/notification/ZenModeDiff.java
+++ b/core/java/android/service/notification/ZenModeDiff.java
@@ -495,8 +495,8 @@
// Even if added or removed, there may be a change in whether or not it was active.
// This only applies to automatic rules.
- boolean fromActive = from != null ? from.isAutomaticActive() : false;
- boolean toActive = to != null ? to.isAutomaticActive() : false;
+ boolean fromActive = from != null ? from.isActive() : false;
+ boolean toActive = to != null ? to.isActive() : false;
if (fromActive != toActive) {
mActiveDiff = new FieldDiff<>(fromActive, toActive);
}
diff --git a/core/java/android/service/quicksettings/TEST_MAPPING b/core/java/android/service/quicksettings/TEST_MAPPING
index 2d45c5b..986dc5f 100644
--- a/core/java/android/service/quicksettings/TEST_MAPPING
+++ b/core/java/android/service/quicksettings/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTileServiceTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTileServiceTestCases"
}
]
}
\ No newline at end of file
diff --git a/core/java/android/service/timezone/TEST_MAPPING b/core/java/android/service/timezone/TEST_MAPPING
index bf46ff2..2071717 100644
--- a/core/java/android/service/timezone/TEST_MAPPING
+++ b/core/java/android/service/timezone/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksTimeCoreTests",
- "options": [
- {
- "include-filter": "android.service."
- }
- ]
+ "name": "FrameworksTimeCoreTests_android_service"
},
{
"name": "CtsLocationTimeZoneManagerHostTest"
diff --git a/core/java/android/speech/TEST_MAPPING b/core/java/android/speech/TEST_MAPPING
index 7b125c2..cb490f5b 100644
--- a/core/java/android/speech/TEST_MAPPING
+++ b/core/java/android/speech/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsVoiceRecognitionTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVoiceRecognitionTestCases"
}
]
}
diff --git a/core/java/android/text/TEST_MAPPING b/core/java/android/text/TEST_MAPPING
index c9bd2ca..9f8a72c 100644
--- a/core/java/android/text/TEST_MAPPING
+++ b/core/java/android/text/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsTextTestCases_text"
}
]
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index f8c97eb..71ceaf7 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -2087,6 +2087,7 @@
/**
* @hide
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public static String stateToString(int state) {
switch (state) {
case STATE_UNKNOWN:
@@ -2109,6 +2110,7 @@
}
/** @hide */
+ @android.ravenwood.annotation.RavenwoodKeep
public static String stateReasonToString(@StateReason int reason) {
switch (reason) {
case STATE_REASON_UNKNOWN:
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index dd950e8..b21e85a 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -174,24 +174,26 @@
@IntDef(prefix = {"POINTER_ICON_VECTOR_STYLE_FILL_"}, value = {
POINTER_ICON_VECTOR_STYLE_FILL_BLACK,
POINTER_ICON_VECTOR_STYLE_FILL_GREEN,
- POINTER_ICON_VECTOR_STYLE_FILL_YELLOW,
+ POINTER_ICON_VECTOR_STYLE_FILL_RED,
POINTER_ICON_VECTOR_STYLE_FILL_PINK,
- POINTER_ICON_VECTOR_STYLE_FILL_BLUE
+ POINTER_ICON_VECTOR_STYLE_FILL_BLUE,
+ POINTER_ICON_VECTOR_STYLE_FILL_PURPLE
})
@Retention(RetentionPolicy.SOURCE)
public @interface PointerIconVectorStyleFill {}
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_BLACK = 0;
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_GREEN = 1;
- /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_YELLOW = 2;
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_RED = 2;
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_PINK = 3;
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_BLUE = 4;
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_PURPLE = 5;
// If adding a PointerIconVectorStyleFill, update END value for {@link SystemSettingsValidators}
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_BEGIN =
POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_END =
- POINTER_ICON_VECTOR_STYLE_FILL_BLUE;
+ POINTER_ICON_VECTOR_STYLE_FILL_PURPLE;
/** @hide */
@IntDef(prefix = {"POINTER_ICON_VECTOR_STYLE_STROKE_"}, value = {
@@ -712,12 +714,14 @@
com.android.internal.R.style.PointerIconVectorStyleFillBlack;
case POINTER_ICON_VECTOR_STYLE_FILL_GREEN ->
com.android.internal.R.style.PointerIconVectorStyleFillGreen;
- case POINTER_ICON_VECTOR_STYLE_FILL_YELLOW ->
- com.android.internal.R.style.PointerIconVectorStyleFillYellow;
+ case POINTER_ICON_VECTOR_STYLE_FILL_RED ->
+ com.android.internal.R.style.PointerIconVectorStyleFillRed;
case POINTER_ICON_VECTOR_STYLE_FILL_PINK ->
com.android.internal.R.style.PointerIconVectorStyleFillPink;
case POINTER_ICON_VECTOR_STYLE_FILL_BLUE ->
com.android.internal.R.style.PointerIconVectorStyleFillBlue;
+ case POINTER_ICON_VECTOR_STYLE_FILL_PURPLE ->
+ com.android.internal.R.style.PointerIconVectorStyleFillPurple;
default -> com.android.internal.R.style.PointerIconVectorStyleFillBlack;
};
}
diff --git a/core/java/android/view/TEST_MAPPING b/core/java/android/view/TEST_MAPPING
index db35908..ac6cd02 100644
--- a/core/java/android/view/TEST_MAPPING
+++ b/core/java/android/view/TEST_MAPPING
@@ -4,39 +4,11 @@
"name": "CtsAccelerationTestCases"
},
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.os.cts.StrictModeTest"
- }
- ],
+ "name": "CtsOsTestCases_cts_strictmodetest_Presubmit",
"file_patterns": ["(/|^)ViewConfiguration.java", "(/|^)GestureDetector.java"]
},
{
- "name": "CtsViewReceiveContentTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ],
+ "name": "CtsViewReceiveContentTestCases_Presubmit",
"file_patterns": ["ContentInfo\\.java", "OnReceiveContentListener\\.java", "View\\.java"]
}
],
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index d2747e4..5129461 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -587,7 +587,14 @@
@Override
public void updateRequestedVisibleTypes(IWindow window,
- @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token imeStatsToken) {
+ @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token imeStatsToken)
+ throws RemoteException {
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ // Embedded windows do not control insets (except for IME). The host window is
+ // responsible for controlling the insets.
+ mRealWm.updateRequestedVisibleTypes(window,
+ requestedVisibleTypes & WindowInsets.Type.ime(), imeStatsToken);
+ }
}
@Override
diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig
index e9c85684..658aa29 100644
--- a/core/java/android/view/flags/scroll_feedback_flags.aconfig
+++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig
@@ -21,4 +21,5 @@
name: "enable_touch_scroll_feedback"
description: "Enables touchscreen haptic scroll feedback"
bug: "331830899"
+ is_fixed_read_only: true
}
diff --git a/core/java/android/view/inputmethod/TEST_MAPPING b/core/java/android/view/inputmethod/TEST_MAPPING
index ad59463..989b686 100644
--- a/core/java/android/view/inputmethod/TEST_MAPPING
+++ b/core/java/android/view/inputmethod/TEST_MAPPING
@@ -1,21 +1,7 @@
{
"presubmit": [
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.inline"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.AppModeFull"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_cts_inline_ExcludeAppModeFull"
}
]
}
diff --git a/core/java/android/view/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING
index 050c651..bc7f3b0 100644
--- a/core/java/android/view/textclassifier/TEST_MAPPING
+++ b/core/java/android/view/textclassifier/TEST_MAPPING
@@ -4,20 +4,10 @@
"name": "FrameworksCoreTests_textclassifier"
},
{
- "name": "CtsTextClassifierTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTextClassifierTestCases"
},
{
- "name": "TextClassifierServiceTest",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TextClassifierServiceTest"
}
]
}
diff --git a/core/java/android/webkit/TEST_MAPPING b/core/java/android/webkit/TEST_MAPPING
index 07f4383..3858059 100644
--- a/core/java/android/webkit/TEST_MAPPING
+++ b/core/java/android/webkit/TEST_MAPPING
@@ -1,28 +1,13 @@
{
"presubmit": [
{
- "name": "CtsWebkitTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsWebkitTestCases"
},
{
- "name": "CtsSdkSandboxWebkitTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSdkSandboxWebkitTestCases"
},
{
- "name": "CtsHostsideWebViewTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsHostsideWebViewTests"
},
{
"name": "GtsWebViewTestCases",
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index c7900e4..668cd01 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -22,6 +22,7 @@
import android.os.Build;
import android.os.ChildZygoteProcess;
import android.os.Process;
+import android.os.UserHandle;
import android.os.ZygoteProcess;
import android.text.TextUtils;
import android.util.Log;
@@ -141,12 +142,14 @@
String abi = sPackage.applicationInfo.primaryCpuAbi;
int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote(
sPackage.applicationInfo, null);
+ final int[] sharedAppGid = {
+ UserHandle.getSharedAppGid(UserHandle.getAppId(sPackage.applicationInfo.uid)) };
sZygote = Process.ZYGOTE_PROCESS.startChildZygote(
"com.android.internal.os.WebViewZygoteInit",
"webview_zygote",
Process.WEBVIEW_ZYGOTE_UID,
Process.WEBVIEW_ZYGOTE_UID,
- null, // gids
+ sharedAppGid, // Access to shared app GID for ART profiles
runtimeFlags,
"webview_zygote", // seInfo
abi, // abi
diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING
index bc71bee..624fa864 100644
--- a/core/java/android/widget/TEST_MAPPING
+++ b/core/java/android/widget/TEST_MAPPING
@@ -10,52 +10,17 @@
"file_patterns": ["Toast\\.java"]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.ToastWindowTest"
- }
- ],
+ "name": "CtsWindowManagerDeviceWindow_window_toastwindowtest",
"file_patterns": ["Toast\\.java"]
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.dropdown.LoginActivityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.AppModeFull"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_dropdown_loginactivitytest"
},
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.dropdown.CheckoutActivityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.AppModeFull"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_dropdown_checkoutactivitytest"
},
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsTextTestCases_text"
}
]
}
diff --git a/core/java/android/widget/inline/TEST_MAPPING b/core/java/android/widget/inline/TEST_MAPPING
index 82c6f61..eb412f1 100644
--- a/core/java/android/widget/inline/TEST_MAPPING
+++ b/core/java/android/widget/inline/TEST_MAPPING
@@ -1,18 +1,7 @@
{
"presubmit-large": [
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-filter": "android.autofillservice.cts.inline"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_cts_inline"
}
]
}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 6e89c49..cc5e583 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -86,10 +86,13 @@
}
flag {
- name: "enable_additional_windows_above_status_bar"
+ name: "enable_handle_input_fix"
namespace: "lse_desktop_experience"
- description: "Allows for additional windows tied to WindowDecoration to be layered between status bar and notification shade."
+ description: "Enables using AdditionalSystemViewContainer to resolve handle input issues."
bug: "316186265"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -114,6 +117,13 @@
}
flag {
+ name: "enable_tile_resizing"
+ namespace: "lse_desktop_experience"
+ description: "Enables drawing a divider bar upon tiling tasks left and right in desktop mode for simultaneous resizing"
+ bug: "351769839"
+}
+
+flag {
name: "respect_orientation_change_for_unresizeable"
namespace: "lse_desktop_experience"
description: "Whether to resize task to respect requested orientation change of unresizeable activity"
@@ -145,6 +155,13 @@
}
flag {
+ name: "enable_resizing_metrics"
+ namespace: "lse_desktop_experience"
+ description: "Whether to enable log collection for task resizing in desktop windowing mode"
+ bug: "341319100"
+}
+
+flag {
name: "enable_caption_compat_inset_force_consumption"
namespace: "lse_desktop_experience"
description: "Enables force-consumption of caption bar insets for immersive apps in freeform"
@@ -243,6 +260,16 @@
}
flag {
+ name: "enable_hold_to_drag_app_handle"
+ namespace: "lse_desktop_experience"
+ description: "Requires hold-to-drag the App Handle when using touchscreen input"
+ bug: "356409496"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "skip_compat_ui_education_in_desktop_mode"
namespace: "lse_desktop_experience"
description: "Ignore Compat UI educations when in Desktop Mode."
@@ -265,3 +292,10 @@
description: "Creates a shell transition when display focus switches."
bug: "356109871"
}
+
+flag {
+ name: "enter_desktop_by_default_on_freeform_displays"
+ namespace: "lse_desktop_experience"
+ description: "Allow entering desktop mode by default on freeform displays"
+ bug: "361419732"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 69b91fd..e1402f8 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -246,15 +246,6 @@
}
flag {
- name: "custom_animations_behind_translucent"
- namespace: "windowing_frontend"
- description: "A change can use its own layer parameters to animate behind a translucent activity"
- bug: "327332488"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-flag {
name: "migrate_predictive_back_transition"
namespace: "windowing_frontend"
description: "Create transition when visibility change from predictive back"
@@ -274,4 +265,4 @@
metadata {
purpose: PURPOSE_BUGFIX
}
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index ebcae27..a5e166b 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -144,9 +144,9 @@
@EnforcePermission("UPDATE_DEVICE_STATS")
void noteGpsSignalQuality(int signalLevel);
@EnforcePermission("UPDATE_DEVICE_STATS")
- void noteScreenState(int state);
+ void noteScreenState(int displayId, int state, int reason);
@EnforcePermission("UPDATE_DEVICE_STATS")
- void noteScreenBrightness(int brightness);
+ void noteScreenBrightness(int displayId, int brightness);
@EnforcePermission("UPDATE_DEVICE_STATS")
void noteUserActivity(int uid, int event);
@EnforcePermission("UPDATE_DEVICE_STATS")
diff --git a/core/java/com/android/internal/infra/TEST_MAPPING b/core/java/com/android/internal/infra/TEST_MAPPING
index 35f0553..092aa20 100644
--- a/core/java/com/android/internal/infra/TEST_MAPPING
+++ b/core/java/com/android/internal/infra/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsRoleTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsRoleTestCases"
},
{
"name": "CtsPermissionTestCases_Platform"
diff --git a/core/java/com/android/internal/os/TEST_MAPPING b/core/java/com/android/internal/os/TEST_MAPPING
index 258f402..4400ed1 100644
--- a/core/java/com/android/internal/os/TEST_MAPPING
+++ b/core/java/com/android/internal/os/TEST_MAPPING
@@ -49,12 +49,7 @@
],
"postsubmit": [
{
- "name": "PowerStatsTests",
- "options": [
- {
- "include-filter": "com.android.server.power.stats.BstatsCpuTimesValidationTest"
- }
- ],
+ "name": "PowerStatsTests_stats_bstatscputimesvalidationtest",
"file_patterns": [
"Kernel[^/]*\\.java"
]
diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
index b873175..39aadfb 100644
--- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
+++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
@@ -18,6 +18,7 @@
import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+import android.aconfig.DeviceProtos;
import android.aconfig.nano.Aconfig;
import android.aconfig.nano.Aconfig.parsed_flag;
import android.aconfig.nano.Aconfig.parsed_flags;
@@ -40,7 +41,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
-import java.util.List;
+import java.util.Arrays;
import java.util.Map;
/**
@@ -54,12 +55,6 @@
public class AconfigFlags {
private static final String LOG_TAG = "AconfigFlags";
- private static final List<String> sTextProtoFilesOnDevice = List.of(
- "/system/etc/aconfig_flags.pb",
- "/system_ext/etc/aconfig_flags.pb",
- "/product/etc/aconfig_flags.pb",
- "/vendor/etc/aconfig_flags.pb");
-
public enum Permission {
READ_WRITE,
READ_ONLY
@@ -73,7 +68,10 @@
Slog.v(LOG_TAG, "Feature disabled, skipped all loading");
return;
}
- for (String fileName : sTextProtoFilesOnDevice) {
+ final var defaultFlagProtoFiles =
+ (Process.myUid() == Process.SYSTEM_UID) ? DeviceProtos.parsedFlagsProtoPaths()
+ : Arrays.asList(DeviceProtos.PATHS);
+ for (String fileName : defaultFlagProtoFiles) {
try (var inputStream = new FileInputStream(fileName)) {
loadAconfigDefaultValues(inputStream.readAllBytes());
} catch (IOException e) {
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index 067e5e88..b23515a 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -37,6 +37,8 @@
*
* Note that if the context is not an UI context(not associated with Display), it will use
* default display.
+ *
+ * If the associated display is not internal, will return 0.
*/
public static float getWindowCornerRadius(Context context) {
final Resources resources = context.getResources();
@@ -44,7 +46,13 @@
return 0f;
}
// Use Context#getDisplayNoVerify() in case the context is not an UI context.
- final String displayUniqueId = context.getDisplayNoVerify().getUniqueId();
+ final Display display = context.getDisplayNoVerify();
+ // The radius is only valid for internal displays, since the corner radius of external or
+ // virtual displays is not known when window corners are configured or are not supported.
+ if (display.getType() != Display.TYPE_INTERNAL) {
+ return 0f;
+ }
+ final String displayUniqueId = display.getUniqueId();
// Radius that should be used in case top or bottom aren't defined.
float defaultRadius = RoundedCorners.getRoundedCornerRadius(resources, displayUniqueId)
- RoundedCorners.getRoundedCornerRadiusAdjustment(resources, displayUniqueId);
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a1dea82..9352413 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"’n App verberg die toestemmingversoek en jou antwoord kan dus nie geverifieer word nie."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tik op \'n kenmerk om dit te begin gebruik:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Kies kenmerke om saam met die toeganklikheidknoppie te gebruik"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Kies kenmerke om saam met die volumesleutelskortpad te gebruik"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> is afgeskakel"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Wysig kortpaaie"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Klaar"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Stel ’n skermslot"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Stel skermslot"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Stel ’n skermslot op dié toestel om jou privaat ruimte te gebruik"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> is nie beskikbaar nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a7b6661..10855c8 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ማያ ገጽ መቆለፊያን ያቀናብሩ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ማያ ገጽ መቆለፊያውን ያቀናብሩ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"የግል ቦታዎን ለመጠቀም፣ በዚህ መሣሪያ ላይ ማያ ገጽ መቆለፊያን ያቀናብሩ"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"መተግበሪያ አይገኝም"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን አይገኝም።"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> አይገኝም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7f02576..623ef23 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1750,8 +1750,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"تعذَّر التحقّق من ردّك بسبب حجب أحد التطبيقات طلب الحصول على الإذن."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"انقر على ميزة لبدء استخدامها:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"اختيار الميزات التي تريد استخدامها مع زر أدوات تمكين الوصول"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"اختيار الميزات التي تريد استخدامها مع اختصار مفتاحَي مستوى الصوت"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"تم إيقاف <xliff:g id="SERVICE_NAME">%s</xliff:g>."</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"تعديل الاختصارات"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"تم"</string>
@@ -2015,6 +2014,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ضبط قفل شاشة"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ضبط قفل الشاشة"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"لاستخدام مساحتك الخاصة، يجب ضبط قفل شاشة على هذا الجهاز"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"التطبيق غير متاح"</string>
<string name="app_blocked_message" msgid="542972921087873023">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> غير متاح الآن."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"تطبيق <xliff:g id="ACTIVITY">%1$s</xliff:g> غير متاح"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index c5ad8ba..ba1095b 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"এটা স্ক্ৰীন লক ছেট কৰক"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"স্ক্ৰীন লক ছেট কৰা"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"আপোনাৰ প্ৰাইভেট স্পে\'চ ব্যৱহাৰ কৰিবলৈ এই ডিভাইচটোত স্ক্ৰীন লক ছেট কৰক"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"এপ্টো উপলব্ধ নহয়"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূৰ্তত <xliff:g id="APP_NAME">%1$s</xliff:g> উপলব্ধ নহয়।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলব্ধ নহয়"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index e93a57b..1b574d1 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Bir tətbiq icazə sorğusunu gizlətdiyi üçün cavabı yoxlamaq mümkün deyil."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Funksiyanı istifadə etmək üçün onun üzərinə toxunun:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Xüsusi imkanlar düyməsinin köməyilə işə salınacaq funksiyaları seçin"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Səs səviyyəsi düyməsinin qısayolu ilə istifadə edəcəyiniz funksiyaları seçin"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> deaktiv edilib"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Qısayolları redaktə edin"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Hazırdır"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran kilidi ayarlayın"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran kilidi ayarlayın"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Bu cihazda ekran kilidi ayarlamaqla şəxsi sahədən istifadə edin"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Tətbiq əlçatan deyil"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hazırda əlçatan deyil."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> əlçatan deyil"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 8f0f4b2..2116a6ef 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2011,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Podesite otključavanje ekrana"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Podesi otključavanje ekrana"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Da biste koristili privatni prostor, podesite otključavanje ekrana na ovom uređaju"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 7a49bf3..0219b6c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2012,6 +2012,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Наладзьце блакіроўку экрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Наладзіць блакіроўку экрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Каб выкарыстоўваць прыватную прастору, на прыладзе неабходна наладзіць блакіроўку экрана"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Праграма недаступная"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" цяпер недаступная."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недаступна: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b6fad9e..93fdf3d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Отговорът ви не може да бъде потвърден, тъй като приложение прикрива заявката за разрешение."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Докоснете дадена функция, за да започнете да я използвате:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Избиране на функции, които да използвате с бутона за достъпност"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Избиране на функции, които да използвате с прекия път чрез бутоните за силата на звука"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Изключихте <xliff:g id="SERVICE_NAME">%s</xliff:g>"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Редактиране на преките пътища"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Готово"</string>
@@ -2011,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Настройте заключване на екрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Заключване на екрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"За да ползвате частното си пространство, настройте заключване на екрана"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"За да изтриете личното пространство, настройте заключване на екрана"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Приложението не е достъпно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"В момента няма достъп до <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> не е налице"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index c434fe9..019068b 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"কোনও অ্যাপ অনুমতির অনুরোধ আড়াল করছে তাই আপনার উত্তর যাচাই করা যাবে না।"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"কোনও ফিচার ব্যবহার করা শুরু করতে, সেটিতে ট্যাপ করুন:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"অ্যাক্সেসিবিলিটি বোতামের সাহায্যে আপনি যেসব ফিচার ব্যবহার করতে চান সেগুলি বেছে নিন"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"ভলিউম কী শর্টকাটের সাহায্যে আপনি যেসব ফিচার ব্যবহার করতে চান সেগুলি বেছে নিন"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> বন্ধ করে দেওয়া হয়েছে"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"শর্টকাট এডিট করুন"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"হয়ে গেছে"</string>
@@ -2011,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"\'স্ক্রিন লক\' সেট-আপ করুন"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"\'স্ক্রিন লক\' ফিচার সেট করুন"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"নিজের প্রাইভেট স্পেস ব্যবহার করতে এই ডিভাইসে \'স্ক্রিন লক\' সেট করুন"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"প্রাইভেট স্পেস মুছে দিতে, এই ডিভাইসে \'স্ক্রিন লক\' সেট করুন।"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"অ্যাপ পাওয়া যাচ্ছে না"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূর্তে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ পাওয়া যাচ্ছে না।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলভ্য নেই"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 91c7701..bdd9f15 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1240,7 +1240,7 @@
<string name="whichHomeApplicationNamed" msgid="5855990024847433794">"Koristi %1$s kao glavnu aplikaciju"</string>
<string name="whichHomeApplicationLabel" msgid="8907334282202933959">"Snimanje slike"</string>
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"Snimanje slike koristeći"</string>
- <string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Snimanje slike koristeći %1$s"</string>
+ <string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Snimite sliku aplikacijom %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Snimanje slike"</string>
<string name="alwaysUse" msgid="3153558199076112903">"Koristiti kao zadanu rezoluciju za ovu akciju."</string>
<string name="use_a_different_app" msgid="4987790276170972776">"Koristi drugu aplikaciju"</string>
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Aplikacija skriva zahtjev za odobrenje, pa se vaš odgovor ne može potvrditi."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Dodirnite funkciju da je počnete koristiti:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Odaberite funkcije koje ćete koristiti s dugmetom Pristupačnost"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Odabir funkcija za korištenje pomoću prečice tipki za jačinu zvuka"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Usluga <xliff:g id="SERVICE_NAME">%s</xliff:g> je isključena"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi prečice"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Gotovo"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Postavite zaključavanje ekrana"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Postavite zaključavanje ekrana"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Za upotrebu privatnog prostora postavite zaključavanje ekrana na uređaju"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Nedostupno: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index cbe9c39..5728aed 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Una aplicació està ocultant la sol·licitud de permís, de manera que la teva resposta no es pot verificar"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toca una funció per començar a utilitzar-la:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Tria les funcions que vols utilitzar amb el botó d\'accessibilitat"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Tria les funcions que vols utilitzar amb la drecera de les tecles de volum"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> s\'ha desactivat"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edita les dreceres"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Fet"</string>
@@ -2012,6 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defineix un bloqueig de pantalla"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Defineix un bloqueig de pantalla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Per utilitzar l\'espai privat, defineix un bloqueig de pantalla en aquest dispositiu"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Per suprimir l\'espai privat, defineix un bloqueig de pantalla en aquest dispositiu."</string>
<string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no està disponible"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 69e6483..8aa1224 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2012,6 +2012,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavte si zámek obrazovky"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastavit zámek obrazovky"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Pokud chcete používat soukromý prostor, nastavte na tomto zařízení zámek obrazovky"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> v tuto chvíli není k dispozici."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> není k dispozici"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index d66ebd90..95e61b9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"En app skjuler anmodningen om tilladelse, så dit svar kan ikke verificeres."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tryk på en funktion for at bruge den:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Vælg, hvilke funktioner du vil bruge med knappen til hjælpefunktioner"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Vælg de funktioner, du vil bruge med genvejen til lydstyrkeknapperne"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> er blevet deaktiveret"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Rediger genveje"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Udfør"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Konfigurer en skærmlås"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Konfigurer skærmlås"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Konfigurer en skærmlås på enheden for at bruge dit private område"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er ikke understøttet"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3879767..41c1e4b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Die Berechtigungsanfrage wird durch eine andere App verdeckt. Daher kann deine Antwort nicht geprüft werden."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Zum Auswählen der gewünschten Funktion tippen:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Funktionen auswählen, die du mit der Schaltfläche \"Bedienungshilfen\" verwenden möchtest"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Funktionen für den Kurzbefehl für die Lautstärketasten auswählen"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> wurde deaktiviert"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kurzbefehle bearbeiten"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Fertig"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Displaysperre einrichten"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Displaysperre einrichten"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Richte zur Nutzung des vertraulichen Profils auf dem Gerät die Displaysperre ein"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nicht verfügbar"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 28a5e55..0556a08 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Μια εφαρμογή αποκρύπτει το αίτημα άδειας, με αποτέλεσμα να μην είναι δυνατή η επαλήθευση της απάντησής σας."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Πατήστε μια λειτουργία για να ξεκινήσετε να τη χρησιμοποιείτε:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Επιλέξτε τις λειτουργίες που θέλετε να χρησιμοποιείτε με το κουμπί προσβασιμότητας."</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Επιλέξτε τις λειτουργίες που θέλετε να χρησιμοποιείτε με τη συντόμευση κουμπιών έντασης ήχου"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Η υπηρεσία <xliff:g id="SERVICE_NAME">%s</xliff:g> έχει απενεργοποιηθεί."</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Επεξεργασία συντομεύσεων"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Τέλος"</string>
@@ -2011,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ρυθμίστε ένα κλείδωμα οθόνης"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ρύθμιση κλειδώματος οθόνης"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ορίστε κλείδωμα οθόνης"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Για να διαγράψετε τον ιδιωτικό χώρο, ορίστε ένα κλείδωμα οθόνης σε αυτή τη συσκευή"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Η εφαρμογή δεν είναι διαθέσιμη"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> δεν διατίθεται"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 70d86e7..086835c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"An app is obscuring the permission request so your response cannot be verified."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tap a feature to start using it:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Choose features to use with the Accessibility button"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Choose features to use with the volume keys shortcut"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> has been turned off"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Done"</string>
@@ -2011,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"To delete private space, set a screen lock on this device"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index dad6333..88a83b5 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2010,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"To delete private space, set a screen lock on this device"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index d3f0c64..ef399b7 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"An app is obscuring the permission request so your response cannot be verified."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tap a feature to start using it:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Choose features to use with the Accessibility button"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Choose features to use with the volume keys shortcut"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> has been turned off"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Done"</string>
@@ -2011,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"To delete private space, set a screen lock on this device"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7c3be15..94ddc43 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"An app is obscuring the permission request so your response cannot be verified."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tap a feature to start using it:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Choose features to use with the Accessibility button"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Choose features to use with the volume keys shortcut"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> has been turned off"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit shortcuts"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Done"</string>
@@ -2011,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"To delete private space, set a screen lock on this device"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 0bcbed7..a0a891e 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2010,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Set a screen lock"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Set screen lock"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"To use your private space, set a screen lock on this device"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"To delete private space, set a screen lock on this device"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 773edd3..12d2756 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Una app está cubriendo la solicitud de permiso, por lo que no se puede verificar tu respuesta."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Presiona una función para comenzar a usarla:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Selecciona las funciones a utilizar con el botón de accesibilidad"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Selecciona las funciones que usarás con la combinación de teclas de volumen"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Se desactivó <xliff:g id="SERVICE_NAME">%s</xliff:g>"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar accesos directos"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Listo"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Configurar bloqueo de pantalla"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Configurar bloqueo de pantalla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar tu espacio privado, configura un bloqueo de pantalla"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e50d5fa..c6ee8ef 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -2011,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Define un bloqueo de pantalla"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Establecer bloqueo de pantalla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar el espacio privado, define un bloqueo de pantalla"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index f313fb2..4389b4b 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Rakendus varjab loataotlust, nii et teie vastust ei saa kinnitada."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Puudutage funktsiooni, et selle kasutamist alustada."</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Valige funktsioonid, mida juurdepääsetavuse nupuga kasutada"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Valige helitugevuse nuppude otsetee funktsioonid"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> on välja lülitatud"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muuda otseteid"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Valmis"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Seadistage ekraanilukk"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Seadistage ekraanilukk"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Seadistage oma privaatse ruumi jaoks seadmele ekraanilukk"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Rakendus ei ole saadaval"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole praegu saadaval."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei ole saadaval"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index b0775d0..56b10d1 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Aplikazio bat baimen-eskaera oztopatzen ari da eta, ondorioz, ezin da egiaztatu erantzuna."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Eginbide bat erabiltzen hasteko, saka ezazu:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Aukeratu zein eginbide erabili nahi duzun Erabilerraztasuna botoiarekin"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Aukeratu zein eginbide erabili nahi duzun bolumen-botoien lasterbidearekin"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Desaktibatu da <xliff:g id="SERVICE_NAME">%s</xliff:g>"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editatu lasterbideak"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Eginda"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ezarri pantailaren blokeoa"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ezarri pantailaren blokeoa"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Eremu pribatua erabiltzeko, ezarri pantailaren blokeoa gailuan"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikazioa ez dago erabilgarri"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ez dago erabilgarri une honetan."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ez dago erabilgarri"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 0c46ed9..34edd03 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"قفل صفحه تنظیم کنید"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"تنظیم قفل صفحه"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"برای استفاده از فضای خصوصی، قفل صفحه تنظیم کنید"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"برنامه در دسترس نیست"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحالحاضر در دسترس نیست."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دردسترس نیست"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index dec5b64..ecc7a3f 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Sovellus peittää lupapyynnön, joten vastaustasi ei voi vahvistaa."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Aloita ominaisuuden käyttö napauttamalla sitä:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Valitse ominaisuudet, joita käytetään esteettömyyspainikkeella"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Valitse ominaisuudet, joita käytetään äänenvoimakkuuspikanäppäimillä"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> on laitettu pois päältä"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muokkaa pikakuvakkeita"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Valmis"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Näytön lukituksen asettaminen"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Aseta näytön lukitus"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Edellyttää näytön lukitusta"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Sovellus ei ole käytettävissä"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole nyt käytettävissä."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei käytettävissä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 7cb9e06..86b83a0 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Une appli masque la demande d\'autorisation de sorte que votre réponse ne peut pas être vérifiée."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toucher une fonctionnalité pour commencer à l\'utiliser :"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Choisir les fonctionnalités à utiliser à l\'aide du bouton d\'accessibilité"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Choisir les fonctionnalités à utiliser avec le raccourci des touches de volume"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> a été désactivé"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifier les raccourcis"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"OK"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Config. Verrouillage d\'écran"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Config. Verrouillage d\'écran"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Configurez verrouillage de l\'écran pour utiliser Espace privé"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"L\'appli n\'est pas accessible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non accessible"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ca3998c..5fa4a3b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Une application masque la demande d\'autorisation. Votre réponse ne peut donc pas être vérifiée."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Appuyez sur une fonctionnalité pour commencer à l\'utiliser :"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Choisir les fonctionnalités à utiliser avec le bouton Accessibilité"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Choisir les fonctionnalités à utiliser avec le raccourci des boutons de volume"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Le service <xliff:g id="SERVICE_NAME">%s</xliff:g> a été désactivé"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifier les raccourcis"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"OK"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Activer verrouillage écran"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Activer verrouillage écran"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Pour utiliser votre espace privé, activez le verrouillage de l\'écran sur cet appareil"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponible"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index e07218c..2f3cffa 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Hai unha aplicación que está ocultando a solicitude de permiso, polo que non se pode verificar a túa resposta."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tocar unha función para comezar a utilizala:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Escoller as funcións que queres utilizar co botón Accesibilidade"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Escolle as funcións que queres utilizar co atallo das teclas de volume"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g>: desactivouse"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atallos"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Feito"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Define un bloqueo de pantalla"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Define un bloqueo de pantalla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espazo privado, define un bloqueo de pantalla"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non está dispoñible"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 2ac70ab..aa190a5 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"સ્ક્રીન લૉક સેટ કરો"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"સ્ક્રીન લૉક સેટ કરો"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"તમારી ખાનગી સ્પેસનો ઉપયોગ કરવા, આ ડિવાઇસ પર સ્ક્રીન લૉક સેટ કરો"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ઉપલબ્ધ નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5f1bb9a..4c76cff 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रीन लॉक सेट करें"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रीन लॉक सेट करें"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"प्राइवेट स्पेस के लिए, इस डिवाइस पर स्क्रीन लॉक सेट करें"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"ऐप्लिकेशन उपलब्ध नहीं है"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> इस समय उपलब्ध नहीं है."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नहीं है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2596de2..bf972b8 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Aplikacija prekriva upit za dopuštenje pa se vaš odgovor ne može potvrditi."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Dodirnite značajku da biste je počeli koristiti:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Odabir značajki za upotrebu pomoću gumba za Pristupačnost"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Odabir značajki za upotrebu pomoću prečaca tipki za glasnoću"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Usluga <xliff:g id="SERVICE_NAME">%s</xliff:g> je isključena"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredite prečace"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Gotovo"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Postavite zaključavanje zaslona"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Postavi zaključavanje zaslona"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Da biste upotrebljavali privatni prostor, postavite zaključavanje zaslona na ovom uređaju"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 09af506..357328c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Az egyik alkalmazás eltakarja az engedélykérelmet, így az Ön válasza nem ellenőrizhető."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Koppintson valamelyik funkcióra a használatához:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Kiválaszthatja a Kisegítő lehetőségek gombbal használni kívánt funkciókat"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Kiválaszthatja a hangerőszabályzó gombokkal használni kívánt funkciókat"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kikapcsolva"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Gyorsparancsszerkesztés"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Kész"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Állítson be képernyőzárat"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Képernyőzár beállítása"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"A privát terület használatához állítson be képernyőzárat"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Az alkalmazás nem hozzáférhető"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> jelenleg nem hozzáférhető."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"A(z) <xliff:g id="ACTIVITY">%1$s</xliff:g> nem áll rendelkezése"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a28f413..5405bb2 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Հավելվածը թաքցնում է թույլտվության հայտը, ուստի ձեր պատասխանը հնարավոր չէ ստուգել։"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Ընտրեք՝ որ գործառույթն օգտագործել"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Ընտրեք գործառույթները, որոնք կբացվեն «Հատուկ գործառույթներ» կոճակի միջոցով"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Ընտրեք գործառույթները, որոնք պետք է բացվեն ձայնի կարգավորման կոճակների միջոցով"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ծառայությունն անջատված է"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Փոփոխել դյուրանցումները"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Պատրաստ է"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Կարգավորեք էկրանի կողպումը"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Կարգավորել էկրանի կողպումը"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Մասնավոր տարածքն օգտագործելու համար այս սարքում կարգավորեք էկրանի կողպումը"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Հավելվածը հասանելի չէ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն այս պահին հասանելի չէ։"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 76c89ea..f5a2a14 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Aplikasi menghalangi permintaan izin sehingga respons Anda tidak dapat diverifikasi."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Ketuk fitur untuk mulai menggunakannya:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Pilih fitur yang akan digunakan dengan tombol aksesibilitas"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Pilih fitur yang akan digunakan dengan pintasan tombol volume"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> telah dinonaktifkan"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit pintasan"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Selesai"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Setel kunci layar"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Setel kunci layar"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Untuk menggunakan ruang privasi, setel kunci layar di perangkat ini"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 057b830..baeaa3f 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Stilltu skjálás"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Stilla skjálás"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Stilltu skjálás í tækinu til að nota leynirými"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ekki í boði"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 29533d5..48766b8 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Un\'app nasconde la tua richiesta di autorizzazione, per cui non abbiamo potuto verificare la tua risposta."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tocca una funzionalità per iniziare a usarla:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Scegli le funzionalità da usare con il pulsante Accessibilità"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Scegli le funzionalità da usare con la scorciatoia tasti del volume"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Il servizio <xliff:g id="SERVICE_NAME">%s</xliff:g> è stato disattivato"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifica scorciatoie"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Fine"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Imposta un blocco schermo"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Imposta il blocco schermo"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Per utilizzare il tuo spazio privato, imposta un blocco schermo sul dispositivo"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string>
<string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non disponibile"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 52b6173..d3f0d98 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"אפליקציה מסתירה את בקשת ההרשאה כך שלא ניתן לאמת את התשובה שלך."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"יש להקיש על תכונה כדי להתחיל להשתמש בה:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"בחירת תכונה לשימוש עם לחצן הנגישות"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"בחירת תכונות לשימוש עם קיצור דרך באמצעות מקשי עוצמת הקול"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"שירות <xliff:g id="SERVICE_NAME">%s</xliff:g> כבוי"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"עריכת קיצורי הדרך"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"סיום"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"הגדרת נעילת מסך"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"הגדרה של נעילת מסך"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"כדי להשתמש במרחב הפרטי יש להגדיר נעילת מסך במכשיר"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
<string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> לא זמינה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 0705b36..bcea959 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2010,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"画面ロックの設定"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"画面ロックを設定"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"プライベート スペースには画面ロックの設定が必要です"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"プライベート スペースを削除するには、このデバイスに画面ロックを設定してください"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"アプリの利用不可"</string>
<string name="app_blocked_message" msgid="542972921087873023">"現在 <xliff:g id="APP_NAME">%1$s</xliff:g> はご利用になれません。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>は利用できません"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index bac2333..9a88e54 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2010,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ეკრანის დაბლოკვის დაყენება"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ეკრანის დაბლოკვის დაყენება"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"კერძო სივრცის გამოსაყენებლად დააყენეთ ამ მოწყობილობაზე ეკრანის დაბლოკვა"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"კერძო სივრცის წასაშლელად დააყენეთ ეკრანის დაბლოკვა ამ მოწყობილობაზე"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"აპი მიუწვდომელია"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ამჟამად მიუწვდომელია."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> მიუწვდომელია"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index d9ee240..29dfbba 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Қолданба рұқсат сұрауын жасырып тұрғандықтан, жауабыңыз расталмайды."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Функцияны пайдалана бастау үшін түртіңіз:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"\"Арнайы мүмкіндіктер\" түймесімен қолданылатын функцияларды таңдаңыз"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Дыбыс деңгейі пернелері тіркесімімен қолданылатын функцияларды таңдаңыз"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> қызметі өшірулі."</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Жылдам пәрмендерді өзгерту"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Дайын"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Экран құлпын орнатыңыз"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Экран құлпын орнату"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Құпия кеңістігіңізді қолдану үшін осы құрылғыда экран құлпын орнатыңыз."</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> қолжетімсіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 1f931c6..aeea5dc 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1216,7 +1216,7 @@
<string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{ផ្កាយមួយក្នុងចំណោមផ្កាយ {max}}other{ផ្កាយ # ក្នុងចំណោមផ្កាយ {max}}}"</string>
<string name="in_progress" msgid="2149208189184319441">"កំពុងដំណើរការ"</string>
<string name="whichApplication" msgid="5432266899591255759">"បញ្ចប់សកម្មភាពដោយប្រើ"</string>
- <string name="whichApplicationNamed" msgid="6969946041713975681">"បញ្ចប់សកម្មភាពដោយប្រើ %1$s"</string>
+ <string name="whichApplicationNamed" msgid="6969946041713975681">"បញ្ចប់សកម្មភាពដោយប្រើ %%1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"បញ្ចប់សកម្មភាព"</string>
<string name="whichViewApplication" msgid="5733194231473132945">"បើកជាមួយ"</string>
<string name="whichViewApplicationNamed" msgid="415164730629690105">"បើកជាមួយ %1$s"</string>
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"កំណត់ការចាក់សោអេក្រង់"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"កំណត់ការចាក់សោអេក្រង់"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ដើម្បីប្រើលំហឯកជនរបស់អ្នក សូមកំណត់ការចាក់សោអេក្រង់នៅលើឧបករណ៍នេះ"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"មិនអាចប្រើកម្មវិធីនេះបានទេ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"មិនអាចប្រើ <xliff:g id="APP_NAME">%1$s</xliff:g> នៅពេលនេះបានទេ។"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"មិនអាចប្រើ <xliff:g id="ACTIVITY">%1$s</xliff:g> បានទេ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 941a1b2..126d55e 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2010,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಸೆಟ್ ಮಾಡಿ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಸೆಟ್ ಮಾಡಿ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ನಿಮ್ಮ ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್ ಅನ್ನು ಬಳಸಲು, ಈ ಸಾಧನದಲ್ಲಿ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಸೆಟ್ ಮಾಡಿ"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್ ಅನ್ನು ಅಳಿಸಲು ಈ ಸಾಧನದಲ್ಲಿ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಸೆಟ್ ಮಾಡಿ"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ಆ್ಯಪ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಇದೀಗ ಲಭ್ಯವಿಲ್ಲ."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ಲಭ್ಯವಿಲ್ಲ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0e47e59..5ed6959 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"앱에서 권한 요청을 가려서 응답을 확인할 수 없습니다."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"기능을 사용하려면 탭하세요"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"접근성 버튼으로 사용할 기능 선택"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"볼륨 키 바로가기로 사용할 기능 선택"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g>이(가) 사용 중지됨"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"단축키 수정"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"완료"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"화면 잠금 설정"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"화면 잠금 설정"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"비공개 스페이스를 사용하려면 이 기기에 화면 잠금을 설정하세요"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"앱을 사용할 수 없습니다"</string>
<string name="app_blocked_message" msgid="542972921087873023">"현재 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱을 사용할 수 없습니다."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 사용할 수 없음"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 43fd6a7..0c3a5e1 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Экран кулпусун коюп алыңыз"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Экран кулпусун коюу"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Жеке мейкиндикти колдонуу үчүн бул түзмөктүн экранын кулпулаңыз"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Колдонмо учурда жеткиликсиз"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> учурда жеткиликсиз"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> жеткиликсиз"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index dc15e9a..fb677cf 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2010,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ຕັ້ງການລັອກໜ້າຈໍ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ຕັ້ງການລັອກໜ້າຈໍ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ເພື່ອໃຊ້ພື້ນທີ່ສ່ວນບຸກຄົນ, ໃຫ້ຕັ້ງລັອກໜ້າຈໍຢູ່ອຸປະກອນນີ້"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"ເພື່ອລຶບພື້ນທີ່ສ່ວນບຸກຄົນ, ໃຫ້ຕັ້ງການລັອກໜ້າຈໍຢູ່ອຸປະກອນນີ້"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ແອັບບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"ບໍ່ສາມາດໃຊ້ <xliff:g id="ACTIVITY">%1$s</xliff:g> ໄດ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8eace89..56945c2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1748,8 +1748,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Programa užstoja leidimo užklausą, todėl negalima patvirtinti jūsų atsakymo."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Norėdami naudoti funkciją, palieskite ją:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Funkcijų, kurioms bus naudojamas pritaikomumo mygtukas, pasirinkimas"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Funkcijų, kurioms bus naudojami garsumo spartieji klavišai, pasirinkimas"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Paslauga „<xliff:g id="SERVICE_NAME">%s</xliff:g>“ išjungta"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redaguoti sparčiuosius klavišus"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Atlikta"</string>
@@ -2013,6 +2012,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekrano užrako nustatymas"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nustatykite ekrano užraktą"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Jei norite naudoti privačią erdvę, nustatykite ekrano užraktą šiame įrenginyje"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string>
<string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"„<xliff:g id="ACTIVITY">%1$s</xliff:g>“ nepasiekiama"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 01fb9da..8b271d9 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Kāda lietotne padara atļaujas pieprasījumu nesaprotamu, tāpēc nevar verificēt jūsu atbildi."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Pieskarieties funkcijai, lai sāktu to izmantot"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Izvēlieties funkcijas, ko izmantot ar pieejamības pogu"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Izvēlieties funkcijas, kuras piešķirt skaļuma pogu saīsnei"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Pakalpojums <xliff:g id="SERVICE_NAME">%s</xliff:g> ir izslēgts."</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Rediģēt īsinājumtaustiņus"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Gatavs"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Iestatiet ekrāna bloķēšanu"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Iestatīt ekrāna bloķēšanu"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Lai izmantotu privāto telpu, iestatiet ekrāna bloķēšanu."</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Lietotne nav pieejama"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pašlaik nav pieejama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nav pieejams"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index dbc4b75..a5ce587 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Апликација го прикрива барањето за дозвола, па вашиот одговор не може да се потврди."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Допрете на функција за да почнете да ја користите:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Изберете ги функциите што ќе ги користите со копчето за пристапност"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Изберете ги функциите што ќе ги користите со кратенката за копчињата за јачина на звук"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> е исклучена"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Изменете ги кратенките"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Готово"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Поставете заклучување екран"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Поставете заклучување екран"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"За да користите „Приватен простор“, поставете заклучување екран на уредов"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Апликацијата не е достапна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> не е достапна во моментов."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> е недостапна"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 6d60696..ef9d6c8 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"സ്വകാര്യ സ്പേസിന്, ഇതിൽ സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കൂ"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"ആപ്പ് ലഭ്യമല്ല"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ലഭ്യമല്ല"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index bf2f78c..01a175a 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Апп зөвшөөрлийн хүсэлтийг хааж байгаа тул таны хариултыг баталгаажуулах боломжгүй."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Үүнийг ашиглаж эхлэхийн тулд онцлог дээр товшино уу:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Хандалтын товчлуурын тусламжтай ашиглах онцлогуудыг сонгоно уу"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Дууны түвшний товчийн товчлолоор ашиглах онцлогуудыг сонгоно уу"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g>-г унтраалаа"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Товчлолуудыг засах"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Болсон"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Дэлгэцийн түгжээ тохируулах"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Дэлгэцийн түгжээ тохируулах"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Хаалттай орон зайгаа ашиглах бол уг төхөөрөмжид дэлгэцийн түгжээ тохируулна уу"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Апп боломжгүй байна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> яг одоо боломжгүй байна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> боломжгүй байна"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 30403cf..f9b70ff 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रीन लॉक सेट करा"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रीन लॉक सेट करा"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"तुमची खाजगी स्पेस वापरण्यास, या डिव्हाइसवर स्क्रीन लॉक सेट करा"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"ॲप उपलब्ध नाही"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> आता उपलब्ध नाही."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index e17c62b..b30d48d 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Tetapkan kunci skrin"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Tetapkan kunci skrin"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Tetapkan kunci skrin pada peranti untuk menggunakan ruang privasi"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Apl tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia sekarang."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 85fb0e9..b78e2cb 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ဖန်သားပြင်လော့ခ် သတ်မှတ်ပါ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ဖန်သားပြင်လော့ခ် သတ်မှတ်ရန်"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"သင့်သီးသန့်နေရာသုံးရန် ဤစက်၌ ဖန်သားပြင်လော့ခ် သတ်မှတ်ပါ"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"အက်ပ်ကို မရနိုင်ပါ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ယခု မရနိုင်ပါ။"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> မရနိုင်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 8feb6e9..8002e90 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"En app dekker forespørselen om tillatelse, så svaret ditt kan ikke bekreftes."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Trykk på en funksjon for å begynne å bruke den:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Velg funksjonene du vil bruke med Tilgjengelighet-knappen"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Velg funksjonene du vil bruke med volumtastsnarveien"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> er slått av"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Endre snarveier"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Ferdig"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Angi en skjermlås"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Angi skjermlås"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"For å bruke det private området, angi en skjermlås på enheten"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgjengelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgjengelig for øyeblikket."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er utilgjengelig"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 36e3254..784cce4 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1216,10 +1216,10 @@
<string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} मा एक तारा}other{{max} मा # तारा}}"</string>
<string name="in_progress" msgid="2149208189184319441">"जारी छ"</string>
<string name="whichApplication" msgid="5432266899591255759">"प्रयोग गरेर कारबाही पुरा गर्नुहोस्"</string>
- <string name="whichApplicationNamed" msgid="6969946041713975681">"निम्न एपको प्रयोग गरी कारबाही पुरा गर्नुहोस्: %1$s"</string>
+ <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s प्रयोग गरी यो कार्य पूरा गर्नुहोस्"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"पूर्ण कारबाही"</string>
<string name="whichViewApplication" msgid="5733194231473132945">"निम्नबाट खोल्नुहोस्"</string>
- <string name="whichViewApplicationNamed" msgid="415164730629690105">"निम्न एपमा खोल्नुहोस्: %1$s"</string>
+ <string name="whichViewApplicationNamed" msgid="415164730629690105">"%1$s मार्फत खोल्नुहोस्"</string>
<string name="whichViewApplicationLabel" msgid="7367556735684742409">"खोल्नुहोस्"</string>
<string name="whichOpenHostLinksWith" msgid="7645631470199397485">"निम्नमार्फत <xliff:g id="HOST">%1$s</xliff:g> का लिंकहरू खोल्नुहोस्"</string>
<string name="whichOpenLinksWith" msgid="1120936181362907258">"निम्नमार्फत लिंकहरू खोल्नुहोस्"</string>
@@ -1227,7 +1227,7 @@
<string name="whichOpenHostLinksWithApp" msgid="2401668560768463004">"<xliff:g id="APPLICATION">%2$s</xliff:g> मार्फत <xliff:g id="HOST">%1$s</xliff:g> का लिंकहरू खोल्नुहोस्"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="7805857277166106236">"पहुँच दिनुहोस्"</string>
<string name="whichEditApplication" msgid="6191568491456092812">"सँग सम्पादन गर्नुहोस्"</string>
- <string name="whichEditApplicationNamed" msgid="8096494987978521514">"%1$s सँग सम्पादन गर्नुहोस्"</string>
+ <string name="whichEditApplicationNamed" msgid="8096494987978521514">"%1$s प्रयोग गरी सम्पादन गर्नुहोस्"</string>
<string name="whichEditApplicationLabel" msgid="1463288652070140285">"सम्पादन गर्नुहोस्"</string>
<string name="whichSendApplication" msgid="4143847974460792029">"सेयर गर्नुहोस्"</string>
<string name="whichSendApplicationNamed" msgid="4470386782693183461">"%1$s सँग सेयर गर्नुहोस्"</string>
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"स्क्रिन लक सेटअप गर्नुहोस्"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"स्क्रिन लक सेटअप गर्नुहोस्"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"निजी स्पेस प्रयोग गर्न यो डिभाइसमा स्क्रिन लक सेटअप गर्नुहोस्"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"एप उपलब्ध छैन"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> अहिले उपलब्ध छैन।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध छैन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 18773f6..6180b1b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Schermvergrendeling instellen"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Schermvergrendeling instellen"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Als je je privégedeelte wilt gebruiken, stel je een schermvergrendeling op dit apparaat in"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> niet beschikbaar"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 45b6e9a..e6e20fa 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"ଏକ ଆପ ଅନୁମତି ଅନୁରୋଧକୁ ଅସ୍ପଷ୍ଟ କରୁଛି ତେଣୁ ଆପଣଙ୍କ ଉତ୍ତରକୁ ଯାଞ୍ଚ କରାଯାଇପାରିବ ନାହିଁ।"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"ଏକ ଫିଚର୍ ବ୍ୟବହାର କରିବା ଆରମ୍ଭ କରିବାକୁ ଏହାକୁ ଟାପ୍ କରନ୍ତୁ:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"ଆକ୍ସେସିବିଲିଟୀ ବଟନ୍ ସହିତ ବ୍ୟବହାର କରିବାକୁ ଫିଚରଗୁଡ଼ିକ ବାଛନ୍ତୁ"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"ଭଲ୍ୟୁମ କୀ ସର୍ଟକଟ ସହିତ ବ୍ୟବହାର କରିବାକୁ ଫିଚରଗୁଡ଼ିକ ବାଛନ୍ତୁ"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ବନ୍ଦ ହୋଇଯାଇଛି"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ସର୍ଟକଟଗୁଡ଼ିକୁ ଏଡିଟ କରନ୍ତୁ"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"ହୋଇଗଲା"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ଏକ ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ଆପଣଙ୍କ ପ୍ରାଇଭେଟ ସ୍ପେସ ବ୍ୟବହାର କରିବାକୁ ଏହି ଡିଭାଇସରେ ଏକ ସ୍କ୍ରିନ ଲକ ସେଟ କରନ୍ତୁ"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c6d0b9f..8afb731 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"ਕੋਈ ਐਪ ਇਜਾਜ਼ਤ ਸੰਬੰਧੀ ਬੇਨਤੀ ਨੂੰ ਅਸਪਸ਼ਟ ਕਰ ਰਹੀ ਹੈ, ਇਸ ਲਈ ਤੁਹਾਡੇ ਜਵਾਬ ਦੀ ਪੁਸ਼ਟੀ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"ਕਿਸੇ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਵਰਤਣਾ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਉਸ \'ਤੇ ਟੈਪ ਕਰੋ:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"ਪਹੁੰਚਯੋਗਤਾ ਬਟਨ ਨਾਲ ਵਰਤਣ ਲਈ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚੁਣੋ"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਦੇ ਸ਼ਾਰਟਕੱਟ ਨਾਲ ਵਰਤਣ ਲਈ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚੁਣੋ"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ਨੂੰ ਬੰਦ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ਸ਼ਾਰਟਕੱਟਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"ਹੋ ਗਿਆ"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ਆਪਣੀ ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਵਰਤਣ ਲਈ, ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਕਰੋ"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 0ae3bbf..14320ffe 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1748,8 +1748,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Aplikacja zasłania prośbę o uprawnienia, więc nie można zweryfikować Twojej odpowiedzi."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Wybierz funkcję, aby zacząć z niej korzystać:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Wybierz funkcje, których chcesz używać z przyciskiem ułatwień dostępu"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Wybierz funkcje, do których chcesz używać skrótu z przyciskami głośności"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Usługa <xliff:g id="SERVICE_NAME">%s</xliff:g> została wyłączona"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edytuj skróty"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"OK"</string>
@@ -2013,6 +2012,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ustaw blokadę ekranu"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ustaw blokadę ekranu"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Aby korzystać z przestrzeni prywatnej, ustaw na tym urządzeniu blokadę ekranu"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – brak dostępu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index e025d19..e8e125c 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Um app está ocultando a solicitação de permissão e impedindo a verificação da sua resposta."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toque em um recurso para começar a usá-lo:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Escolha recursos para usar com o botão de acessibilidade"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Escolha recursos para usar com o atalho das teclas de volume"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"O <xliff:g id="SERVICE_NAME">%s</xliff:g> foi desativado"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Concluído"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defina um bloqueio de tela"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Definir bloqueio de tela"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espaço privado, defina um bloqueio de tela neste dispositivo"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 28c130c..910c5cf 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -2011,6 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defina um bloqueio de ecrã"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Definir bloqueio de ecrã"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Defina um bloqueio para usar o espaço privado"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Para eliminar o espaço privado, defina um bloqueio de ecrã neste dispositivo"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index e025d19..e8e125c 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Um app está ocultando a solicitação de permissão e impedindo a verificação da sua resposta."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toque em um recurso para começar a usá-lo:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Escolha recursos para usar com o botão de acessibilidade"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Escolha recursos para usar com o atalho das teclas de volume"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"O <xliff:g id="SERVICE_NAME">%s</xliff:g> foi desativado"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Concluído"</string>
@@ -2012,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Defina um bloqueio de tela"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Definir bloqueio de tela"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para usar o espaço privado, defina um bloqueio de tela neste dispositivo"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7e5e7c0..85f8592 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1747,8 +1747,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"O aplicație blochează solicitarea de permisiune, așa că răspunsul nu se poate verifica."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Atinge o funcție ca să începi să o folosești:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Alege funcțiile pe care să le folosești cu butonul de accesibilitate"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Alege funcțiile pentru comanda rapidă a butoanelor de volum"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> a fost dezactivat"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editează comenzile rapide"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Gata"</string>
@@ -2012,6 +2011,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Setează o blocare a ecranului"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Setează blocarea ecranului"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ca să folosești spațiul privat, setează blocarea ecranului pe acest dispozitiv"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"Ca să ștergi spațiul privat, setează o blocare a ecranului pe acest dispozitiv"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplicația nu este disponibilă"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu este disponibilă momentan."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nu este disponibilă"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 3c374ef..29b9d17 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2012,6 +2012,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Настройте блокировку экрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Настроить блокировку экрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Чтобы использовать частное пространство, настройте блокировку экрана на этом устройстве."</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Приложение недоступно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" сейчас недоступно."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index af835d9..acd6d43 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1057,7 +1057,7 @@
<string name="lockscreen_access_pattern_cell_added_verbose" msgid="2931364927622563465">"<xliff:g id="CELL_INDEX">%1$s</xliff:g> කොටුව එකතු කරන ලදි"</string>
<string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"රටාව සම්පූර්ණයි"</string>
<string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"රටා ප්රදේශය."</string>
- <string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%1$s. %3$d න් %2$d විජටය."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%%1$s. %%3$d න් %%2$d විජටය."</string>
<string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"විජටය එක් කරන්න."</string>
<string name="keyguard_accessibility_widget_empty_slot" msgid="544239307077644480">"හිස්"</string>
<string name="keyguard_accessibility_unlock_area_expanded" msgid="7768634718706488951">"අගුළු අරින ප්රදේශය විදහා ඇත."</string>
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"යෙදුමක් අවසර ඉල්ලීම අඳුරු කරන බැවින්, ඔබේ ප්රතිචාරය සත්යාපනය කළ නොහැක."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"එය භාවිත කිරීම ආරම්භ කිරීමට විශේෂාංගයක් තට්ටු කරන්න:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"ප්රවේශ්යතා බොත්තම සමග භාවිත කිරීමට විශේෂාංග තෝරා ගන්න"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"හඬ පරිමා යතුරු කෙටිමග සමග භාවිත කිරීමට විශේෂාංග තෝරා ගන්න"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ක්රියාවිරහිත කර ඇත"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"කෙටිමං සංස්කරණ කරන්න"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"නිමයි"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"තිර අගුලක් සකසන්න"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"තිර අගුල සකසන්න"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ඔබේ රහසිගත අවකාශය භාවිතා කිරීමට, මෙම උපාංගයේ තිර අගුලක් සකසන්න"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"යෙදුම ලබා ගත නොහැකිය"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> මේ දැන් ලබා ගත නොහැකිය."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> නොතිබේ"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 7185bcd..07b44f9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2012,6 +2012,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavte zámku obrazovky"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastaviť zámku obrazovky"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ak chcete používať súkromný priestor, nastavte v tomto zariadení zámku obrazovky"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nie je k dispozícii"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e67bf9c..f3b0da4 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2012,6 +2012,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Nastavitev zaklepanja zaslona"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Nastavite zaklepanje zaslona"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Če želite uporabljati zasebni prostor, v tej napravi nastavite zaklepanje zaslona"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"»<xliff:g id="ACTIVITY">%1$s</xliff:g>« ni na voljo"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index d8fe109..badb90d 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Një aplikacion po fsheh kërkesën për leje, prandaj përgjigja jote nuk mund të verifikohet."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Trokit te një veçori për të filluar ta përdorësh atë:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Zgjidh veçoritë që do të përdorësh me butonin e qasshmërisë"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Zgjidh veçoritë që do të përdorësh me shkurtoren e tasteve të volumit"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> është çaktivizuar"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redakto shkurtoret"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"U krye"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Cakto një kyçje ekrani"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Cakto kyçjen e ekranit"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Për të përdorur hapësirën private, cakto një kyçje ekrani në këtë pajisje"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nuk ofrohet"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index f5988c2..d38dd12 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2011,6 +2011,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Подесите откључавање екрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Подеси откључавање екрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Да бисте користили приватни простор, подесите откључавање екрана на овом уређају"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> тренутно није доступна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – није доступно"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 9bde6af..9b7f3a1 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"En app döljer behörighetsbegäran så det går inte att verifiera svaret."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tryck på funktioner som du vill aktivera:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Välj vilka funktioner du vill använda med hjälp av tillgänglighetsknappen"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Välj funktioner att använda med hjälp av volymknappskortkommandot"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> har inaktiverats"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redigera genvägar"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Klar"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ställ in ett skärmlås"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ställ in skärmlås"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ställ in ett skärmlås för enheten om du vill använda ditt privata område."</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> är inte tillgänglig"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index c286eeb..e1123af 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Programu inazuia ombi la ruhusa kwa hivyo jibu lako haliwezi kuthibitishwa."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Gusa kipengele ili uanze kukitumia:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Chagua vipengele vya kutumia na kitufe cha zana za ufikivu"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Chagua vipengele vya kutumia kupitia njia ya mkato ya vitufe vya sauti"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Huduma ya <xliff:g id="SERVICE_NAME">%s</xliff:g> imezimwa"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kubadilisha njia za mkato"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Nimemaliza"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Weka mbinu ya kufunga skrini"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Weka mbinu ya kufunga skrini"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ili utumie sehemu ya faragha, weka mbinu ya kufunga skrini kwenye kifaa hiki"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> haipatikani"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 626205e..f167eb7 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"திரைப் பூட்டை அமையுங்கள்"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"திரைப் பூட்டை அமை"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"ரகசிய இடத்தைப் பயன்படுத்த, சாதனத்தில் திரைப் பூட்டை அமையுங்கள்"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"இந்த ஆப்ஸ் இப்போது கிடைப்பதில்லை"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் இப்போது கிடைப்பதில்லை."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> இல்லை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index db19868..1f8a2f7 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2010,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"స్క్రీన్ లాక్ను సెట్ చేయండి"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"స్క్రీన్ లాక్ను సెట్ చేయండి"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"మీ ప్రైవేట్ స్పేస్ను ఉపయోగించడానికి, ఈ పరికరంలో స్క్రీన్ లాక్ సెట్ చేయండి"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"ప్రైవేట్ స్పేస్ను తొలగించడానికి, ఈ పరికరంలో స్క్రీన్ లాక్ను సెట్ చేయండి"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"యాప్ అందుబాటులో లేదు"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> అందుబాటులో లేదు"</string>
@@ -2152,7 +2153,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"సరే"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ఆఫ్ చేయండి"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"మరింత తెలుసుకోండి"</string>
- <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో Android అనుకూల నోటిఫికేషన్లను, మెరుగైన నోటిఫికేషన్లు రీప్లేస్ చేశాయి. ఈ ఫీచర్, సూచించిన చర్యలను, రిప్లయిలను చూపించి, మీ నోటిఫికేషన్లను ఆర్గనైజ్ చేస్తుంది.\n\nకాంటాక్ట్ పేర్లు, మెసేజ్లు లాంటి వ్యక్తిగత సమాచారంతో పాటు నోటిఫికేషన్ కంటెంట్ను మెరుగైన నోటిఫికేషన్లు యాక్సెస్ చేస్తాయి. ఫోన్ కాల్స్కు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్ను కంట్రోల్ చేయడం వంటి నోటిఫికేషన్లను విస్మరించడం లేదా వాటికి ప్రతిస్పందించడం కూడా ఈ ఫీచర్ చేయగలదు."</string>
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో \'మెరుగైన నోటిఫికేషన్లు\', \'Android అనుకూల నోటిఫికేషన్ల\'ను రీప్లేస్ చేశాయి. చేయాల్సిన పనులను, రిప్లయిలను ఈ ఫీచర్ మీకు చూపిస్తుంది. అలాగే మీ నోటిఫికేషన్లను ఆర్గనైజ్ చేస్తుంది. \n\nనోటిఫికేషన్ కంటెంట్ను \'మెరుగైన నోటిఫికేషన్లు\' ఫీచర్ యాక్సెస్ చేయగలదు. కాంటాక్ట్ పేర్లు, మెసేజ్ల వంటి వ్యక్తిగత సమాచారం కూడా ఈ కంటెంట్లో ఉంటుంది. ఈ ఫీచర్, నోటిఫికేషన్లను విస్మరించగలదు (డిస్మిస్ చేయగలదు) లేదా వాటికి ప్రతిస్పందించగలదు (రెస్పాండ్ కాగలదు). ఫోన్ కాల్స్కు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్ను కంట్రోల్ చేయడం లాంటి పనులు కూడా ఇందులో ఉంటాయి."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string>
<string name="dynamic_mode_notification_title" msgid="1388718452788985481">"బ్యాటరీ సేవర్ ఆన్ చేయబడింది"</string>
<string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"బ్యాటరీ జీవితకాలాన్ని పొడిగించడానికి బ్యాటరీ వినియోగాన్ని తగ్గించడం"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index b34cf59..cc716ea 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"ตั้งล็อกหน้าจอ"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"ตั้งล็อกหน้าจอ"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"หากต้องการใช้พื้นที่ส่วนตัว ให้ตั้งการล็อกหน้าจอในอุปกรณ์นี้"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"แอปไม่พร้อมใช้งาน"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่พร้อมใช้งานในขณะนี้"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b976f20..8939120 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2010,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Magtakda ng lock ng screen"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Itakda ang lock ng screen"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Para gamitin ang iyong pribadong space, magtakda ng lock ng screen sa device na ito."</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Hindi available ang app"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Hindi available sa ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Hindi available ang <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a015a8f..85fea5c 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Bir uygulama, izin isteğini gizlediğinden yanıtınız doğrulanamıyor."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Kullanmaya başlamak için bir özelliğe dokunun:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Erişilebilirlik düğmesiyle kullanılacak özellikleri seçin"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Ses seviyesi tuşları kısayoluyla kullanılacak özellikleri seçin"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> kapatıldı"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kısayolları düzenle"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Bitti"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran kilidi ayarlayın"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran kilidi ayarla"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Özel alanı kullanmak için cihazda ekran kilidi ayarlayın"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Uygulama kullanılamıyor"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması şu anda kullanılamıyor."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kullanılamıyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e41d3ce..614925f 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1748,8 +1748,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Інший додаток перекриває запит на доступ, тому вашу відповідь не вдається підтвердити."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Натисніть функцію, щоб почати використовувати її:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Виберіть функції для кнопки спеціальних можливостей"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Виберіть функції для швидких дій клавішами гучності"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Сервіс <xliff:g id="SERVICE_NAME">%s</xliff:g> вимкнено"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Змінити"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Готово"</string>
@@ -2013,6 +2012,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Налаштуйте блокування екрана"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Налаштувати блокування екрана"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Для доступу до приватного простору налаштуйте блокування екрана"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Додаток недоступний"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зараз недоступний."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index fcfff0f..660068d 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2010,6 +2010,7 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"اسکرین لاک سیٹ کریں"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"اسکرین لاک سیٹ کریں"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"اپنی نجی اسپیس استعمال کرنے کیلئے، اس آلہ پر اسکرین لاک سیٹ کریں"</string>
+ <string name="private_space_set_up_screen_lock_for_reset" msgid="7817091386408432097">"پرائیویٹ اسپیس استعمال کرنے کیلئے، اس آلہ پر اسکرین لاک سیٹ کریں"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ایپ دستیاب نہیں ہے"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ابھی دستیاب نہیں ہے۔"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دستیاب نہیں ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index e9bc805..7bd6175 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Ilova ruxsat olish talabini berkitmoqda, shu sababdan javobingizni tasdiqlash imkonsiz."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Kerakli funksiyani tanlang"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Qulayliklar tugmasi bilan foydalanish uchun funksiyalarni tanlang"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Tovush tugmasi bilan ishga tushiriladigan funksiyalarni tanlang"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> faolsizlantirildi"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Tezkor tugmalarni tahrirlash"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"OK"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Ekran qulfini sozlash"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Ekran qulfini sozlash"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Maxfiy makon ishlatish uchun bu qurilma ekran qulfini sozlang"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kanali ish faoliyatida emas"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 510edab..f084c37c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Một ứng dụng đang che khuất yêu cầu quyền này nên chúng tôi không thể xác minh phản hồi của bạn."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Nhấn vào một tính năng để bắt đầu sử dụng:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Chọn các tính năng để dùng với nút hỗ trợ tiếp cận"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Chọn các tính năng để dùng với lối tắt cho phím âm lượng"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> đã bị tắt"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Chỉnh sửa phím tắt"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Xong"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Đặt phương thức khoá màn hình"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Đặt phương thức khoá màn hình"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Để dùng không gian riêng tư, hãy thiết lập một phương thức khoá màn hình trên thiết bị này"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Ứng dụng này không dùng được"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện không dùng được."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Không hỗ trợ <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index bcb54dc..a1c36ab 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"应用遮挡了权限请求,因此我们无法验证您的回复。"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"点按相应功能即可开始使用:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"选择可通过“无障碍”按钮使用的功能"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"选择可通过音量键快捷方式使用的功能"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"已关闭<xliff:g id="SERVICE_NAME">%s</xliff:g>"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"修改快捷方式"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"完成"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"设置一种屏锁方式"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"设置屏锁方式"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"若要使用私密空间,请在此设备上设置屏锁方式"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"应用无法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前无法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>不可用"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 875eec0..6a5fea7 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"有應用程式阻擋權限要求,因此系統無法驗證你的回應。"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"輕按即可開始使用所需功能:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"選擇要配搭無障礙功能按鈕使用的功能"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"選擇要用音量鍵捷徑的功能"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> 已關閉"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"編輯捷徑"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"完成"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"設定螢幕鎖定"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"設定螢幕鎖定"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"如要使用私人空間,請在此裝置上設定螢幕鎖定功能"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"無法使用應用程式"</string>
<string name="app_blocked_message" msgid="542972921087873023">"目前無法使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法使用「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index efa4c51..bb64ab5 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"應用程式遮擋了權限要求,因此系統無法驗證你的回覆。"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"輕觸即可開始使用所需功能:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"選擇要搭配無障礙工具按鈕使用的功能"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"選擇要搭配音量鍵捷徑使用的功能"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"「<xliff:g id="SERVICE_NAME">%s</xliff:g>」已關閉"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"編輯捷徑"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"完成"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"設定螢幕鎖定功能"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"設定螢幕鎖定功能"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"如要使用私人空間,請在這部裝置設定螢幕鎖定功能"</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"應用程式無法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前無法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法存取「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 67a4361..0524c09 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1746,8 +1746,7 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"I-app ifihla isicelo semvume ngakho impendulo yakho ayikwazi ukuqinisekiswa."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Thepha isici ukuqala ukusisebenzisa:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Khetha izici ongazisebenzisa nenkinobho yokufinyeleleka"</string>
- <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
- <skip />
+ <string name="accessibility_edit_shortcut_menu_volume_title" msgid="2245540598834891500">"Khetha izakhi ongazisebenzisa nesinqamuleli sokhiye bevolumu"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"I-<xliff:g id="SERVICE_NAME">%s</xliff:g> ivaliwe"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Hlela izinqamuleli"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Kwenziwe"</string>
@@ -2011,6 +2010,8 @@
<string name="set_up_screen_lock_title" msgid="8346083801616474030">"Setha ukukhiya isikrini"</string>
<string name="set_up_screen_lock_action_label" msgid="2687634803649209367">"Setha ukukhiya isikrini"</string>
<string name="private_space_set_up_screen_lock_message" msgid="1109956797005149814">"Ukuze usebenzise isikhala esigodliwe, setha ukukhiya kwesikrini kule divayisi."</string>
+ <!-- no translation found for private_space_set_up_screen_lock_for_reset (7817091386408432097) -->
+ <skip />
<string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
<string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"okungatholakali <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f6267f6..421b7d2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5834,6 +5834,13 @@
should also be non-empty.-->
<string name="config_rawContactsLocalAccountType" translatable="false"></string>
+ <!-- The array of account types that accounts in any of these can be set as the default account
+ for new raw contacts. -->
+ <string-array name="config_rawContactsEligibleDefaultAccountTypes" translatable="false">
+ <!-- Add account types here, example: -->
+ <!-- <item>com.google</item> -->
+ </string-array>
+
<!-- Whether or not to use assistant stream volume separately from music volume -->
<bool name="config_useAssistantVolume">false</bool>
@@ -7089,6 +7096,10 @@
<!-- Maximum number of active tasks on a given Desktop Windowing session. Set to 0 for unlimited. -->
<integer name="config_maxDesktopWindowingActiveTasks">0</integer>
+ <!-- Whether a display enters desktop mode by default when the windowing mode of the display's
+ root TaskDisplayArea is set to WINDOWING_MODE_FREEFORM. -->
+ <bool name="config_enterDesktopByDefaultOnFreeformDisplay">false</bool>
+
<!-- Frame rate compatibility value for Wallpaper
FRAME_RATE_COMPATIBILITY_MIN (102) is used by default for lower power consumption -->
<integer name="config_wallpaperFrameRateCompatibility">102</integer>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index dc99634..579dc91 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1509,7 +1509,7 @@
</style>
<!-- @hide -->
- <style name="PointerIconVectorStyleFillYellow">
+ <style name="PointerIconVectorStyleFillRed">
<item name="pointerIconVectorFill">#F55E57</item>
<item name="pointerIconVectorFillInverse">#F55E57</item>
</style>
@@ -1527,6 +1527,12 @@
</style>
<!-- @hide -->
+ <style name="PointerIconVectorStyleFillPurple">
+ <item name="pointerIconVectorFill">#AD72FF</item>
+ <item name="pointerIconVectorFillInverse">#AD72FF</item>
+ </style>
+
+ <!-- @hide -->
<style name="PointerIconVectorStyleStrokeWhite">
<item name="pointerIconVectorStroke">@color/white</item>
<item name="pointerIconVectorStrokeInverse">@color/black</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bd8077e..0396659 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1705,9 +1705,10 @@
<java-symbol type="style" name="VectorPointer" />
<java-symbol type="style" name="PointerIconVectorStyleFillBlack" />
<java-symbol type="style" name="PointerIconVectorStyleFillGreen" />
- <java-symbol type="style" name="PointerIconVectorStyleFillYellow" />
+ <java-symbol type="style" name="PointerIconVectorStyleFillRed" />
<java-symbol type="style" name="PointerIconVectorStyleFillPink" />
<java-symbol type="style" name="PointerIconVectorStyleFillBlue" />
+ <java-symbol type="style" name="PointerIconVectorStyleFillPurple" />
<java-symbol type="attr" name="pointerIconVectorFill" />
<java-symbol type="style" name="PointerIconVectorStyleStrokeWhite" />
<java-symbol type="style" name="PointerIconVectorStyleStrokeBlack" />
@@ -4504,6 +4505,7 @@
<!-- For contacts provider. -->
<java-symbol type="string" name="config_rawContactsLocalAccountName" />
<java-symbol type="string" name="config_rawContactsLocalAccountType" />
+ <java-symbol type="array" name="config_rawContactsEligibleDefaultAccountTypes" />
<!-- For App Standby -->
<java-symbol type="string" name="as_app_forced_to_restricted_bucket" />
@@ -5541,6 +5543,10 @@
<!-- Maximum number of active tasks on a given Desktop Windowing session. Set to 0 for unlimited. -->
<java-symbol type="integer" name="config_maxDesktopWindowingActiveTasks"/>
+ <!-- Whether a display enters desktop mode by default when the windowing mode of the display's
+ root TaskDisplayArea is set to WINDOWING_MODE_FREEFORM. -->
+ <java-symbol type="bool" name="config_enterDesktopByDefaultOnFreeformDisplay" />
+
<!-- Frame rate compatibility value for Wallpaper -->
<java-symbol type="integer" name="config_wallpaperFrameRateCompatibility" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index ef6ff05..0837b45 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -215,6 +215,25 @@
}
@Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void testGetShortCriticalText_noneSet() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .build();
+
+ assertSame(n.getShortCriticalText(), null);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_API_RICH_ONGOING)
+ public void testGetShortCriticalText_isSet() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setShortCriticalText("short critical text here")
+ .build();
+
+ assertSame(n.getShortCriticalText(), "short critical text here");
+ }
+
+ @Test
public void largeIconMultipleReferences_keptAfterParcelling() {
Icon originalIcon = Icon.createWithBitmap(BitmapFactory.decodeResource(
mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
diff --git a/core/tests/coretests/src/android/content/pm/TEST_MAPPING b/core/tests/coretests/src/android/content/pm/TEST_MAPPING
index 9ab438e..b350d7d 100644
--- a/core/tests/coretests/src/android/content/pm/TEST_MAPPING
+++ b/core/tests/coretests/src/android/content/pm/TEST_MAPPING
@@ -6,21 +6,7 @@
],
"postsubmit": [
{
- "name": "FrameworksCoreTests",
- "options": [
- {
- "include-filter": "android.content.pm."
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksCoreTests_android_content_pm_PostSubmit"
}
]
}
diff --git a/core/tests/coretests/src/android/os/IpcDataCacheTest.java b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
index b03fd64..64f77b3 100644
--- a/core/tests/coretests/src/android/os/IpcDataCacheTest.java
+++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
@@ -18,7 +18,9 @@
import static org.junit.Assert.assertEquals;
+import android.multiuser.Flags;
import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
@@ -151,8 +153,6 @@
tester.verify(9);
}
- // This test is disabled pending an sepolicy change that allows any app to set the
- // test property.
@Test
public void testRemoteCall() {
@@ -193,6 +193,44 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_CACHING_DEVELOPMENT_IMPROVEMENTS)
+ public void testRemoteCallBypass() {
+
+ // A stand-in for the binder. The test verifies that calls are passed through to
+ // this class properly.
+ ServerProxy tester = new ServerProxy();
+
+ // Create a cache that uses simple arithmetic to computer its values.
+ IpcDataCache.Config config = new IpcDataCache.Config(4, MODULE, API, "testCache3");
+ IpcDataCache<Integer, Boolean> testCache =
+ new IpcDataCache<>(config, (x) -> tester.query(x), (x) -> x % 9 == 0);
+
+ IpcDataCache.setTestMode(true);
+ testCache.testPropertyName();
+
+ tester.verify(0);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(1);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(2);
+ testCache.invalidateCache();
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(3);
+ assertEquals(tester.value(5), testCache.query(5));
+ tester.verify(4);
+ assertEquals(tester.value(5), testCache.query(5));
+ tester.verify(4);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(4);
+ assertEquals(tester.value(9), testCache.query(9));
+ tester.verify(5);
+ assertEquals(tester.value(3), testCache.query(3));
+ tester.verify(5);
+ assertEquals(tester.value(5), testCache.query(5));
+ tester.verify(5);
+ }
+
+ @Test
public void testDisableCache() {
// A stand-in for the binder. The test verifies that calls are passed through to
diff --git a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp
index e0f1012..74c7b4c 100644
--- a/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp
+++ b/core/tests/overlaytests/handle_config_change/test-apps/OverlayResApp/Android.bp
@@ -32,8 +32,8 @@
"truth",
],
libs: [
- "android.test.runner",
- "android.test.base",
+ "android.test.runner.stubs.system",
+ "android.test.base.stubs.system",
],
test_suites: [
"device-tests",
diff --git a/core/tests/vibrator/TEST_MAPPING b/core/tests/vibrator/TEST_MAPPING
index 54a5ff1..d91b883 100644
--- a/core/tests/vibrator/TEST_MAPPING
+++ b/core/tests/vibrator/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksVibratorCoreTests",
- "options": [
- {"exclude-annotation": "androidx.test.filters.LargeTest"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksVibratorCoreTests"
}
],
"postsubmit": [
diff --git a/graphics/TEST_MAPPING b/graphics/TEST_MAPPING
index 8afc30d..75cb87c 100644
--- a/graphics/TEST_MAPPING
+++ b/graphics/TEST_MAPPING
@@ -1,23 +1,10 @@
{
"presubmit": [
{
- "name": "CtsGraphicsTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsGraphicsTestCases"
},
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ],
+ "name": "CtsTextTestCases_text",
"file_patterns": ["(/|^)Typeface\\.java", "(/|^)Paint\\.java"]
}
]
diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java
index 0a6fb84..63ca3b8 100644
--- a/graphics/java/android/graphics/Gainmap.java
+++ b/graphics/java/android/graphics/Gainmap.java
@@ -18,7 +18,9 @@
import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -26,6 +28,9 @@
import libcore.util.NativeAllocationRegistry;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Gainmap represents a mechanism for augmenting an SDR image to produce an HDR one with variable
* display adjustment capability. It is a combination of a set of metadata describing how to apply
@@ -83,6 +88,27 @@
*/
public final class Gainmap implements Parcelable {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"GAINMAP_DIRECTION_"},
+ value = {GAINMAP_DIRECTION_SDR_TO_HDR,
+ GAINMAP_DIRECTION_HDR_TO_SDR})
+ public @interface GainmapDirection {}
+
+ /**
+ * The gainmap will be applied as if the base image were SDR, and fully applying the gainmap
+ * results in an HDR image.
+ */
+ @FlaggedApi(Flags.FLAG_ISO_GAINMAP_APIS)
+ public static final int GAINMAP_DIRECTION_SDR_TO_HDR = 0;
+
+ /**
+ * The gainmap will be applied as if the base image were HDR, and fully applying the gainmap
+ * results in an SDR image.
+ */
+ @FlaggedApi(Flags.FLAG_ISO_GAINMAP_APIS)
+ public static final int GAINMAP_DIRECTION_HDR_TO_SDR = 1;
+
// Use a Holder to allow static initialization of Gainmap in the boot image.
private static class NoImagePreloadHolder {
public static final NativeAllocationRegistry sRegistry =
@@ -252,8 +278,9 @@
}
/**
- * Sets the hdr/sdr ratio at which point the gainmap is fully applied.
- * @param max The hdr/sdr ratio at which the gainmap is fully applied. Must be >= 1.0f
+ * Sets the hdr/sdr ratio at which point applying the gainmap results in an HDR rendition.
+ * @param max The hdr/sdr ratio at which point applying the gainmap results in an HDR rendition.
+ * Must be >= 1.0f
*/
public void setDisplayRatioForFullHdr(@FloatRange(from = 1.0f) float max) {
if (!Float.isFinite(max) || max < 1f) {
@@ -264,7 +291,7 @@
}
/**
- * Gets the hdr/sdr ratio at which point the gainmap is fully applied.
+ * Gets the hdr/sdr ratio at which point applying the gainmap results in an HDR rendition
*/
@NonNull
public float getDisplayRatioForFullHdr() {
@@ -272,8 +299,9 @@
}
/**
- * Sets the hdr/sdr ratio below which only the SDR image is displayed.
- * @param min The minimum hdr/sdr ratio at which to begin applying the gainmap. Must be >= 1.0f
+ * Sets the hdr/sdr ratio below which applying the gainmap results in an SDR rendition.
+ * @param min The minimum hdr/sdr ratio at which point applying the gainmap results in an SDR
+ * rendition. Must be >= 1.0f
*/
public void setMinDisplayRatioForHdrTransition(@FloatRange(from = 1.0f) float min) {
if (!Float.isFinite(min) || min < 1f) {
@@ -284,7 +312,7 @@
}
/**
- * Gets the hdr/sdr ratio below which only the SDR image is displayed.
+ * Gets the hdr/sdr ratio below which applying the gainmap results in an SDR rendition.
*/
@NonNull
public float getMinDisplayRatioForHdrTransition() {
@@ -292,6 +320,55 @@
}
/**
+ * Sets the colorspace that the gainmap math should be applied in.
+ * Only the primaries are what is relevant for applying the gainmap. The transfer and range
+ * characteritics are ignored.
+ *
+ * If the supplied ColorSpace is null, then applying the gainmap will be done using the color
+ * gamut of the base image.
+ */
+ @FlaggedApi(Flags.FLAG_ISO_GAINMAP_APIS)
+ public void setAlternativeImagePrimaries(@Nullable ColorSpace colorSpace) {
+ long colorSpaceInstance = colorSpace == null ? 0 : colorSpace.getNativeInstance();
+ nSetAlternativeColorSpace(mNativePtr, colorSpaceInstance);
+ }
+
+ /**
+ * Gets the colorspace that the gainmap math should be applied in.
+ * Only the primaries are what is relevant for applying the gainmap. The transfer and range
+ * characteritics are ignored.
+ *
+ * If the returned ColorSpace is null, then applying the gainmap will be done using the color
+ * gamut of the base image.
+ */
+ @FlaggedApi(Flags.FLAG_ISO_GAINMAP_APIS)
+ @Nullable
+ public ColorSpace getAlternativeImagePrimaries() {
+ return nGetAlternativeColorSpace(mNativePtr);
+ }
+
+ /**
+ * Sets the direction that the gainmap math should be applied in.
+ */
+ @FlaggedApi(Flags.FLAG_ISO_GAINMAP_APIS)
+ public void setGainmapDirection(@GainmapDirection int direction) {
+ if (direction != GAINMAP_DIRECTION_SDR_TO_HDR
+ && direction != GAINMAP_DIRECTION_HDR_TO_SDR) {
+ throw new IllegalArgumentException("Invalid gainmap direction: " + direction);
+ }
+ nSetDirection(mNativePtr, direction);
+ }
+
+ /**
+ * Gets the direction that the gainmap math should be applied in.
+ */
+ @FlaggedApi(Flags.FLAG_ISO_GAINMAP_APIS)
+ public @GainmapDirection int getGainmapDirection() {
+ return nGetDirection(mNativePtr);
+ }
+
+
+ /**
* No special parcel contents.
*/
@Override
@@ -361,6 +438,10 @@
private static native void nSetDisplayRatioSdr(long ptr, float min);
private static native float nGetDisplayRatioSdr(long ptr);
+ private static native void nSetAlternativeColorSpace(long ptr, long colorSpacePtr);
+ private static native ColorSpace nGetAlternativeColorSpace(long ptr);
+ private static native void nSetDirection(long ptr, int direction);
+ private static native int nGetDirection(long ptr);
private static native void nWriteGainmapToParcel(long ptr, Parcel dest);
private static native void nReadGainmapFromParcel(long ptr, Parcel src);
}
diff --git a/graphics/java/android/graphics/TEST_MAPPING b/graphics/java/android/graphics/TEST_MAPPING
index df91222..5cc31ba 100644
--- a/graphics/java/android/graphics/TEST_MAPPING
+++ b/graphics/java/android/graphics/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ],
+ "name": "CtsTextTestCases_text",
"file_patterns": [
"Typeface\\.java",
"Paint\\.java",
diff --git a/graphics/java/android/graphics/drawable/TEST_MAPPING b/graphics/java/android/graphics/drawable/TEST_MAPPING
index 4f06452..da0a721 100644
--- a/graphics/java/android/graphics/drawable/TEST_MAPPING
+++ b/graphics/java/android/graphics/drawable/TEST_MAPPING
@@ -1,14 +1,8 @@
{
"presubmit": [
{
-
- "name": "CtsGraphicsTestCases",
- "file_patterns": ["(/|^)Icon\\.java"],
- "options" : [
- {
- "include-filter": "android.graphics.drawable.cts.IconTest"
- }
- ]
+ "name": "CtsGraphicsTestCases_cts_icontest",
+ "file_patterns": ["(/|^)Icon\\.java"]
},
{
diff --git a/graphics/java/android/graphics/fonts/TEST_MAPPING b/graphics/java/android/graphics/fonts/TEST_MAPPING
index 99cbfe7..9f8a72c 100644
--- a/graphics/java/android/graphics/fonts/TEST_MAPPING
+++ b/graphics/java/android/graphics/fonts/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsTextTestCases_text"
}
]
}
diff --git a/graphics/java/android/graphics/pdf/TEST_MAPPING b/graphics/java/android/graphics/pdf/TEST_MAPPING
index afec35c..8720b95 100644
--- a/graphics/java/android/graphics/pdf/TEST_MAPPING
+++ b/graphics/java/android/graphics/pdf/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPdfTestCases",
- "options": [
- {
- "include-filter": "android.graphics.pdf.cts.PdfDocumentTest"
- }
- ]
+ "name": "CtsPdfTestCases_cts_pdfdocumenttest"
}
]
}
diff --git a/graphics/java/android/graphics/text/TEST_MAPPING b/graphics/java/android/graphics/text/TEST_MAPPING
index 99cbfe7..9f8a72c 100644
--- a/graphics/java/android/graphics/text/TEST_MAPPING
+++ b/graphics/java/android/graphics/text/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTextTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsTextTestCases_text"
}
]
}
diff --git a/libs/WindowManager/Jetpack/src/TEST_MAPPING b/libs/WindowManager/Jetpack/src/TEST_MAPPING
index f8f6400..600c79b 100644
--- a/libs/WindowManager/Jetpack/src/TEST_MAPPING
+++ b/libs/WindowManager/Jetpack/src/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "WMJetpackUnitTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "WMJetpackUnitTests_Presubmit"
},
{
- "name": "CtsWindowManagerJetpackTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "CtsWindowManagerJetpackTestCases_Presubmit"
}
],
"imports": [
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index c6044a45..394093c6 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,6 @@
[email protected]
[email protected]
[email protected]
# Give submodule owners in shell resource approval
per-file res*/*/*.xml = [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
index 1871203..b6db6d9 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
@@ -72,8 +72,8 @@
"platform-screenshot-diff-core",
],
libs: [
- "android.test.base",
- "android.test.runner",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
jni_libs: [
"libdexmakerjvmtiagent",
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_manage_windows.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_manage_windows.xml
new file mode 100644
index 0000000..7d912a2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_ic_handle_menu_manage_windows.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
+ <path android:fillColor="@android:color/black" android:pathData="M160,880Q127,880 103.5,856.5Q80,833 80,800L80,440Q80,407 103.5,383.5Q127,360 160,360L240,360L240,160Q240,127 263.5,103.5Q287,80 320,80L800,80Q833,80 856.5,103.5Q880,127 880,160L880,520Q880,553 856.5,576.5Q833,600 800,600L720,600L720,800Q720,833 696.5,856.5Q673,880 640,880L160,880ZM160,800L640,800Q640,800 640,800Q640,800 640,800L640,520L160,520L160,800Q160,800 160,800Q160,800 160,800ZM720,520L800,520Q800,520 800,520Q800,520 800,520L800,240L320,240L320,360L640,360Q673,360 696.5,383.5Q720,407 720,440L720,520Z"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_dialog_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_dialog_background.xml
index e7c89d1..f37fb8d 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_dialog_background.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_dialog_background.xml
@@ -17,6 +17,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/>
<corners android:radius="@dimen/letterbox_education_dialog_corner_radius"/>
</shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml
index 72ebef6..3fdd059 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml
@@ -32,7 +32,7 @@
</item>
<item>
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorAccentPrimaryVariant"/>
+ <solid android:color="?androidprv:attr/materialColorPrimary"/>
<corners android:radius="@dimen/letterbox_education_dialog_button_radius"/>
<padding android:left="@dimen/letterbox_education_dialog_horizontal_padding"
android:top="@dimen/letterbox_education_dialog_vertical_padding"
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml
index 4a1e748..67929df 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml
@@ -18,10 +18,13 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:width="@dimen/letterbox_education_dialog_title_icon_width"
android:height="@dimen/letterbox_education_dialog_title_icon_height"
- android:viewportWidth="45"
- android:viewportHeight="44">
-
- <path
- android:fillColor="?androidprv:attr/colorAccentPrimaryVariant"
- android:pathData="M11 40H19C19 42.2 17.2 44 15 44C12.8 44 11 42.2 11 40ZM7 38L23 38V34L7 34L7 38ZM30 19C30 26.64 24.68 30.72 22.46 32L7.54 32C5.32 30.72 0 26.64 0 19C0 10.72 6.72 4 15 4C23.28 4 30 10.72 30 19ZM26 19C26 12.94 21.06 8 15 8C8.94 8 4 12.94 4 19C4 23.94 6.98 26.78 8.7 28L21.3 28C23.02 26.78 26 23.94 26 19ZM39.74 14.74L37 16L39.74 17.26L41 20L42.26 17.26L45 16L42.26 14.74L41 12L39.74 14.74ZM35 12L36.88 7.88L41 6L36.88 4.12L35 0L33.12 4.12L29 6L33.12 7.88L35 12Z" />
+ android:viewportWidth="32"
+ android:viewportHeight="32">
+ <group>
+ <clip-path
+ android:pathData="M0,0h32v32h-32z"/>
+ <path
+ android:pathData="M5.867,22.667C4.489,21.844 3.389,20.733 2.567,19.333C1.744,17.933 1.333,16.378 1.333,14.667C1.333,12.067 2.233,9.867 4.033,8.067C5.856,6.244 8.067,5.333 10.667,5.333C13.267,5.333 15.467,6.244 17.267,8.067C19.089,9.867 20,12.067 20,14.667C20,16.378 19.589,17.933 18.767,19.333C17.944,20.733 16.844,21.844 15.467,22.667H5.867ZM6.667,20H14.667C15.511,19.356 16.167,18.578 16.633,17.667C17.1,16.733 17.333,15.733 17.333,14.667C17.333,12.822 16.678,11.256 15.367,9.967C14.078,8.656 12.511,8 10.667,8C8.822,8 7.244,8.656 5.933,9.967C4.644,11.256 4,12.822 4,14.667C4,15.733 4.233,16.733 4.7,17.667C5.167,18.578 5.822,19.356 6.667,20ZM7.2,26.667C6.822,26.667 6.5,26.544 6.233,26.3C5.989,26.033 5.867,25.711 5.867,25.333C5.867,24.956 5.989,24.644 6.233,24.4C6.5,24.133 6.822,24 7.2,24H14.133C14.511,24 14.822,24.133 15.067,24.4C15.333,24.644 15.467,24.956 15.467,25.333C15.467,25.711 15.333,26.033 15.067,26.3C14.822,26.544 14.511,26.667 14.133,26.667H7.2ZM10.667,30.667C9.933,30.667 9.3,30.411 8.767,29.9C8.256,29.367 8,28.733 8,28H13.333C13.333,28.733 13.067,29.367 12.533,29.9C12.022,30.411 11.4,30.667 10.667,30.667ZM24.667,13.367C24.667,11.7 24.078,10.278 22.9,9.1C21.722,7.922 20.3,7.333 18.633,7.333C20.3,7.333 21.722,6.756 22.9,5.6C24.078,4.422 24.667,3 24.667,1.333C24.667,3 25.244,4.422 26.4,5.6C27.578,6.756 29,7.333 30.667,7.333C29,7.333 27.578,7.922 26.4,9.1C25.244,10.278 24.667,11.7 24.667,13.367Z"
+ android:fillColor="?androidprv:attr/materialColorPrimary"/>
+ </group>
</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_reposition.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_reposition.xml
index 22a8f39..29e58a1 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_reposition.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_reposition.xml
@@ -15,16 +15,16 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/letterbox_education_dialog_icon_width"
- android:height="@dimen/letterbox_education_dialog_icon_height"
- android:viewportWidth="40"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="32"
android:viewportHeight="32">
<path
+ android:pathData="M4,4C2.527,4 1.333,5.194 1.333,6.667V25.333C1.333,26.806 2.527,28 4,28H28C29.472,28 30.666,26.806 30.666,25.333V6.667C30.666,5.194 29.472,4 28,4H4ZM28,6.667H4V25.333H28V6.667Z"
android:fillColor="@color/letterbox_education_text_secondary"
- android:fillType="evenOdd"
- android:pathData="M4 0C1.79086 0 0 1.79086 0 4V28C0 30.2091 1.79086 32 4 32H36C38.2091 32 40 30.2091 40 28V4C40 1.79086 38.2091 0 36 0H4ZM36 4H4V28H36V4Z" />
+ android:fillType="evenOdd" />
<path
- android:fillColor="@color/letterbox_education_text_secondary"
- android:pathData="M19.98 8L17.16 10.82L20.32 14L12 14V18H20.32L17.14 21.18L19.98 24L28 16.02L19.98 8Z" />
+ android:pathData="M17.32,10.667L15.44,12.547L17.546,14.667L9.333,14.667L9.333,17.333H17.546L15.426,19.453L17.32,21.333L22.666,16.013L17.32,10.667Z"
+ android:fillColor="@color/letterbox_education_text_secondary" />
</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_split_screen.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_split_screen.xml
index 15e65f7..6a766d3 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_split_screen.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_split_screen.xml
@@ -17,10 +17,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/letterbox_education_dialog_icon_width"
android:height="@dimen/letterbox_education_dialog_icon_height"
- android:viewportWidth="40"
- android:viewportHeight="32">
+ android:viewportWidth="28"
+ android:viewportHeight="22">
<path
android:fillColor="@color/letterbox_education_text_secondary"
- android:pathData="M40 28L40 4C40 1.8 38.2 -7.86805e-08 36 -1.74846e-07L26 -6.11959e-07C23.8 -7.08124e-07 22 1.8 22 4L22 28C22 30.2 23.8 32 26 32L36 32C38.2 32 40 30.2 40 28ZM14 28L4 28L4 4L14 4L14 28ZM18 28L18 4C18 1.8 16.2 -1.04033e-06 14 -1.1365e-06L4 -1.57361e-06C1.8 -1.66978e-06 -7.86805e-08 1.8 -1.74846e-07 4L-1.22392e-06 28C-1.32008e-06 30.2 1.8 32 4 32L14 32C16.2 32 18 30.2 18 28Z" />
+ android:pathData="M27.333,19L27.333,3C27.333,1.533 26.133,0.333 24.666,0.333L18,0.333C16.533,0.333 15.333,1.533 15.333,3L15.333,19C15.333,20.467 16.533,21.667 18,21.667L24.666,21.667C26.133,21.667 27.333,20.467 27.333,19ZM10,19L3.333,19L3.333,3L10,3L10,19ZM12.666,19L12.666,3C12.666,1.533 11.466,0.333 10,0.333L3.333,0.333C1.866,0.333 0.666,1.533 0.666,3L0.666,19C0.666,20.467 1.866,21.667 3.333,21.667L10,21.667C11.466,21.667 12.666,20.467 12.666,19Z" />
</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml
index 1f12514..4207482 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml
@@ -32,7 +32,7 @@
</item>
<item>
<shape android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorAccentPrimaryVariant"/>
+ <solid android:color="?androidprv:attr/materialColorPrimary"/>
<corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/>
<padding android:left="@dimen/letterbox_restart_dialog_horizontal_padding"
android:top="@dimen/letterbox_restart_dialog_vertical_padding"
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml
index e3c18a2..72cfeef 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml
@@ -17,6 +17,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/>
<corners android:radius="@dimen/letterbox_restart_dialog_corner_radius"/>
</shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml
index 3aa0981..816b350 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml
@@ -32,9 +32,9 @@
</item>
<item>
<shape android:shape="rectangle">
- <stroke android:color="?androidprv:attr/colorAccentPrimaryVariant"
+ <stroke android:color="?androidprv:attr/materialColorOutlineVariant"
android:width="1dp"/>
- <solid android:color="?androidprv:attr/colorSurface"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/>
<corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/>
<padding android:left="@dimen/letterbox_restart_dialog_horizontal_padding"
android:top="@dimen/letterbox_restart_dialog_vertical_padding"
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml
index 5053971..f13d26c 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml
@@ -18,15 +18,13 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:width="@dimen/letterbox_restart_dialog_title_icon_width"
android:height="@dimen/letterbox_restart_dialog_title_icon_height"
- android:viewportWidth="45"
- android:viewportHeight="44">
- <group
- android:scaleX="0.8"
- android:scaleY="0.8"
- android:translateX="8"
- android:translateY="8">
+ android:viewportWidth="32"
+ android:viewportHeight="32">
+ <group>
+ <clip-path
+ android:pathData="M0,0h32v32h-32z"/>
<path
- android:pathData="M0,36V24.5H3V30.85L10.4,23.45L12.55,25.6L5.15,33H11.5V36H0ZM24.5,36V33H30.85L23.5,25.65L25.65,23.5L33,30.85V24.5H36V36H24.5ZM10.35,12.5L3,5.15V11.5H0V0H11.5V3H5.15L12.5,10.35L10.35,12.5ZM25.65,12.5L23.5,10.35L30.85,3H24.5V0H36V11.5H33V5.15L25.65,12.5Z"
- android:fillColor="?androidprv:attr/colorAccentPrimaryVariant"/>
+ android:pathData="M8.533,25.333H10.667C11.044,25.333 11.356,25.467 11.6,25.733C11.867,25.978 12,26.289 12,26.667C12,27.044 11.867,27.367 11.6,27.633C11.356,27.878 11.044,28 10.667,28H5.333C4.956,28 4.633,27.878 4.367,27.633C4.122,27.367 4,27.044 4,26.667V21.333C4,20.956 4.122,20.644 4.367,20.4C4.633,20.133 4.956,20 5.333,20C5.711,20 6.022,20.133 6.267,20.4C6.533,20.644 6.667,20.956 6.667,21.333V23.467L9.867,20.267C10.111,20.022 10.422,19.9 10.8,19.9C11.178,19.9 11.489,20.022 11.733,20.267C11.978,20.511 12.1,20.822 12.1,21.2C12.1,21.578 11.978,21.889 11.733,22.133L8.533,25.333ZM23.467,25.333L20.267,22.133C20.022,21.889 19.9,21.578 19.9,21.2C19.9,20.822 20.022,20.511 20.267,20.267C20.511,20.022 20.822,19.9 21.2,19.9C21.578,19.9 21.889,20.022 22.133,20.267L25.333,23.467V21.333C25.333,20.956 25.456,20.644 25.7,20.4C25.967,20.133 26.289,20 26.667,20C27.044,20 27.356,20.133 27.6,20.4C27.867,20.644 28,20.956 28,21.333V26.667C28,27.044 27.867,27.367 27.6,27.633C27.356,27.878 27.044,28 26.667,28H21.333C20.956,28 20.633,27.878 20.367,27.633C20.122,27.367 20,27.044 20,26.667C20,26.289 20.122,25.978 20.367,25.733C20.633,25.467 20.956,25.333 21.333,25.333H23.467ZM6.667,8.533V10.667C6.667,11.044 6.533,11.367 6.267,11.633C6.022,11.878 5.711,12 5.333,12C4.956,12 4.633,11.878 4.367,11.633C4.122,11.367 4,11.044 4,10.667V5.333C4,4.956 4.122,4.644 4.367,4.4C4.633,4.133 4.956,4 5.333,4H10.667C11.044,4 11.356,4.133 11.6,4.4C11.867,4.644 12,4.956 12,5.333C12,5.711 11.867,6.033 11.6,6.3C11.356,6.544 11.044,6.667 10.667,6.667H8.533L11.733,9.867C11.978,10.111 12.1,10.422 12.1,10.8C12.1,11.178 11.978,11.489 11.733,11.733C11.489,11.978 11.178,12.1 10.8,12.1C10.422,12.1 10.111,11.978 9.867,11.733L6.667,8.533ZM25.333,8.533L22.133,11.733C21.889,11.978 21.578,12.1 21.2,12.1C20.822,12.1 20.511,11.978 20.267,11.733C20.022,11.489 19.9,11.178 19.9,10.8C19.9,10.422 20.022,10.111 20.267,9.867L23.467,6.667H21.333C20.956,6.667 20.633,6.544 20.367,6.3C20.122,6.033 20,5.711 20,5.333C20,4.956 20.122,4.644 20.367,4.4C20.633,4.133 20.956,4 21.333,4H26.667C27.044,4 27.356,4.133 27.6,4.4C27.867,4.644 28,4.956 28,5.333V10.667C28,11.044 27.867,11.367 27.6,11.633C27.356,11.878 27.044,12 26.667,12C26.289,12 25.967,11.878 25.7,11.633C25.456,11.367 25.333,11.044 25.333,10.667V8.533Z"
+ android:fillColor="?androidprv:attr/materialColorPrimary"/>
</group>
</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
index eea3de8..64f71c7 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
@@ -147,6 +147,14 @@
android:drawableStart="@drawable/desktop_mode_ic_handle_menu_new_window"
android:drawableTint="?androidprv:attr/materialColorOnSurface"
style="@style/DesktopModeHandleMenuActionButton" />
+
+ <Button
+ android:id="@+id/manage_windows_button"
+ android:contentDescription="@string/manage_windows_text"
+ android:text="@string/manage_windows_text"
+ android:drawableStart="@drawable/desktop_mode_ic_handle_menu_manage_windows"
+ android:drawableTint="?androidprv:attr/materialColorOnSurface"
+ style="@style/DesktopModeHandleMenuActionButton" />
</LinearLayout>
<LinearLayout
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml
index c77a4fd..bda087b 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml
@@ -24,10 +24,10 @@
<ImageView
android:id="@+id/letterbox_education_dialog_action_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
android:layout_gravity="center"
- android:layout_marginBottom="20dp"/>
+ android:layout_marginBottom="12dp"/>
<TextView
android:fontFamily="@*android:string/config_bodyFontFamily"
@@ -37,7 +37,7 @@
android:layout_height="wrap_content"
android:lineSpacingExtra="4sp"
android:textAlignment="center"
- android:textColor="?android:attr/textColorSecondary"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
android:textSize="14sp"/>
</LinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
index 4d52567..488123a 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
@@ -45,19 +45,16 @@
android:layout_height="wrap_content">
<LinearLayout
+ android:padding="24dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
- android:orientation="vertical"
- android:paddingTop="32dp"
- android:paddingBottom="32dp"
- android:paddingLeft="56dp"
- android:paddingRight="56dp">
+ android:orientation="vertical">
<ImageView
android:layout_width="@dimen/letterbox_education_dialog_title_icon_width"
android:layout_height="@dimen/letterbox_education_dialog_title_icon_height"
- android:layout_marginBottom="17dp"
+ android:layout_marginBottom="16dp"
android:src="@drawable/letterbox_education_ic_light_bulb"/>
<TextView
@@ -67,9 +64,8 @@
android:lineSpacingExtra="4sp"
android:text="@string/letterbox_education_dialog_title"
android:textAlignment="center"
- android:textColor="?android:attr/textColorPrimary"
- android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"
+ android:textColor="?androidprv:attr/materialColorOnSurface"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
android:textSize="24sp"/>
<LinearLayout
@@ -77,7 +73,8 @@
android:layout_height="wrap_content"
android:gravity="top"
android:orientation="horizontal"
- android:paddingTop="48dp">
+ android:layout_marginHorizontal="18dp"
+ android:layout_marginVertical="@dimen/letterbox_education_dialog_margin">
<com.android.wm.shell.compatui.LetterboxEduDialogActionLayout
android:layout_width="wrap_content"
@@ -101,15 +98,13 @@
android:lineHeight="20dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Small"
android:id="@+id/letterbox_education_dialog_dismiss_button"
- android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="56dp"
- android:layout_marginTop="40dp"
android:textSize="14sp"
android:background=
"@drawable/letterbox_education_dismiss_button_background_ripple"
android:text="@string/letterbox_education_got_it"
- android:textColor="?android:attr/textColorPrimaryInverse"
+ android:textColor="?androidprv:attr/materialColorOnPrimary"
android:textAlignment="center"
android:contentDescription="@string/letterbox_education_got_it"/>
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
index 7f1aac3..045b975 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_restart_dialog_layout.xml
@@ -70,26 +70,27 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/letterbox_restart_dialog_description"
- android:textAlignment="center"/>
+ android:gravity="start"/>
<LinearLayout
android:id="@+id/letterbox_restart_dialog_checkbox_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingVertical="14dp"
+ android:paddingVertical="16dp"
android:orientation="horizontal"
android:layout_gravity="center_vertical"
- android:layout_marginVertical="18dp">
+ android:layout_marginVertical="16dp">
<CheckBox
android:id="@+id/letterbox_restart_dialog_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
android:button="@drawable/letterbox_restart_checkbox_button"/>
<TextView
android:textAppearance="@style/RestartDialogCheckboxText"
- android:layout_marginStart="12dp"
+ android:layout_marginStart="20dp"
android:id="@+id/letterbox_restart_dialog_checkbox_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -101,16 +102,19 @@
<FrameLayout
android:minHeight="@dimen/letterbox_restart_dialog_button_height"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_gravity="end">
<Button
android:textAppearance="@style/RestartDialogDismissButton"
android:id="@+id/letterbox_restart_dialog_dismiss_button"
+ style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginRight="8dp"
android:minWidth="@dimen/letterbox_restart_dialog_button_width"
android:minHeight="@dimen/letterbox_restart_dialog_button_height"
- android:layout_gravity="start"
android:background=
"@drawable/letterbox_restart_dismiss_button_background_ripple"
android:text="@string/letterbox_restart_cancel"
@@ -119,11 +123,11 @@
<Button
android:textAppearance="@style/RestartDialogConfirmButton"
android:id="@+id/letterbox_restart_dialog_restart_button"
+ style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="@dimen/letterbox_restart_dialog_button_width"
android:minHeight="@dimen/letterbox_restart_dialog_button_height"
- android:layout_gravity="end"
android:background=
"@drawable/letterbox_restart_button_background_ripple"
android:text="@string/letterbox_restart_restart"
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 8644780..0dd0a99 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -73,8 +73,7 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"contraer <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Configuración de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Descartar burbuja"</string>
- <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
- <skip />
+ <string name="bubble_fullscreen_text" msgid="1006758103218086231">"Mover a pantalla completa"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar la conversación en burbuja"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat con burbujas"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como elementos flotantes o burbujas. Presiona para abrir la burbuja. Arrástrala para moverla."</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 9718bf1..6df154d 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -73,8 +73,7 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"contraer <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Ajustes de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Cerrar burbuja"</string>
- <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
- <skip />
+ <string name="bubble_fullscreen_text" msgid="1006758103218086231">"Cambiar a pantalla completa"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar conversación en burbuja"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatea con burbujas"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como iconos flotantes llamados \"burbujas\". Toca una burbuja para abrirla. Arrástrala para moverla."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 63b5994..92f579d 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -73,8 +73,7 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"Réduire <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Paramètres <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Fermer la bulle"</string>
- <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
- <skip />
+ <string name="bubble_fullscreen_text" msgid="1006758103218086231">"Passer en plein écran"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher la conversation dans une bulle"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatter en utilisant des bulles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou de bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 3ba6873..5f9c492 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -73,8 +73,7 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"comprimi <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Impostazioni <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignora bolla"</string>
- <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
- <skip />
+ <string name="bubble_fullscreen_text" msgid="1006758103218086231">"Passa a schermo intero"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mettere la conversazione nella bolla"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatta utilizzando le bolle"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Le nuove conversazioni vengono mostrate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index cf18da6..b7aa158 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -16,7 +16,8 @@
* limitations under the License.
*/
-->
-<resources>
+<resources
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<color name="docked_divider_handle">#ffffff</color>
<color name="split_divider_background">@color/taskbar_background_dark</color>
<drawable name="forced_resizable_background">#59000000</drawable>
@@ -42,7 +43,7 @@
<color name="compat_controls_text">@android:color/system_neutral1_50</color>
<!-- Letterbox Education -->
- <color name="letterbox_education_text_secondary">@android:color/system_neutral2_200</color>
+ <color name="letterbox_education_text_secondary">?androidprv:attr/materialColorSecondary</color>
<!-- Letterbox Dialog -->
<color name="letterbox_dialog_background">@android:color/system_neutral1_900</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 755e0d5..3d87183 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -304,31 +304,31 @@
<dimen name="letterbox_education_dialog_corner_radius">28dp</dimen>
<!-- The width of the top icon in the letterbox education dialog. -->
- <dimen name="letterbox_education_dialog_title_icon_width">45dp</dimen>
+ <dimen name="letterbox_education_dialog_title_icon_width">32dp</dimen>
<!-- The height of the top icon in the letterbox education dialog. -->
- <dimen name="letterbox_education_dialog_title_icon_height">44dp</dimen>
+ <dimen name="letterbox_education_dialog_title_icon_height">32dp</dimen>
<!-- The width of an icon in the letterbox education dialog. -->
- <dimen name="letterbox_education_dialog_icon_width">40dp</dimen>
+ <dimen name="letterbox_education_dialog_icon_width">28dp</dimen>
<!-- The height of an icon in the letterbox education dialog. -->
- <dimen name="letterbox_education_dialog_icon_height">32dp</dimen>
+ <dimen name="letterbox_education_dialog_icon_height">22dp</dimen>
<!-- The fixed width of the dialog if there is enough space in the parent. -->
- <dimen name="letterbox_education_dialog_width">472dp</dimen>
+ <dimen name="letterbox_education_dialog_width">364dp</dimen>
<!-- The margin between the dialog container and its parent. -->
- <dimen name="letterbox_education_dialog_margin">16dp</dimen>
+ <dimen name="letterbox_education_dialog_margin">24dp</dimen>
<!-- The width of each action container in the letterbox education dialog -->
- <dimen name="letterbox_education_dialog_action_width">140dp</dimen>
+ <dimen name="letterbox_education_dialog_action_width">124dp</dimen>
<!-- The space between two actions in the letterbox education dialog -->
- <dimen name="letterbox_education_dialog_space_between_actions">24dp</dimen>
+ <dimen name="letterbox_education_dialog_space_between_actions">32dp</dimen>
<!-- The corner radius of the buttons in the letterbox education dialog -->
- <dimen name="letterbox_education_dialog_button_radius">12dp</dimen>
+ <dimen name="letterbox_education_dialog_button_radius">28dp</dimen>
<!-- The horizontal padding for the buttons in the letterbox education dialog -->
<dimen name="letterbox_education_dialog_horizontal_padding">16dp</dimen>
@@ -367,7 +367,7 @@
<dimen name="letterbox_restart_dialog_button_width">82dp</dimen>
<!-- The width of the buttons in the restart dialog -->
- <dimen name="letterbox_restart_dialog_button_height">36dp</dimen>
+ <dimen name="letterbox_restart_dialog_button_height">40dp</dimen>
<!-- The corner radius of the buttons in the restart dialog -->
<dimen name="letterbox_restart_dialog_button_radius">18dp</dimen>
@@ -504,9 +504,9 @@
<!-- The width of the handle menu in desktop mode. -->
<dimen name="desktop_mode_handle_menu_width">216dp</dimen>
- <!-- The maximum height of the handle menu in desktop mode. Four pills (52dp each) plus 2dp
- spacing between them plus 4dp top padding. -->
- <dimen name="desktop_mode_handle_menu_height">270dp</dimen>
+ <!-- The maximum height of the handle menu in desktop mode. Three pills at 52dp each,
+ additional actions pill 156dp, plus 2dp spacing between them plus 4dp top padding. -->
+ <dimen name="desktop_mode_handle_menu_height">322dp</dimen>
<!-- The elevation set on the handle menu pills. -->
<dimen name="desktop_mode_handle_menu_pill_elevation">1dp</dimen>
@@ -520,6 +520,9 @@
<!-- The maximum height of the handle menu's "New Window" button in desktop mode. -->
<dimen name="desktop_mode_handle_menu_new_window_height">52dp</dimen>
+ <!-- The maximum height of the handle menu's "Manage Windows" button in desktop mode. -->
+ <dimen name="desktop_mode_handle_menu_manage_windows_height">52dp</dimen>
+
<!-- The maximum height of the handle menu's "Screenshot" button in desktop mode. -->
<dimen name="desktop_mode_handle_menu_screenshot_height">52dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index a353db7..a6da421 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -294,6 +294,8 @@
<string name="open_in_browser_text">Open in browser</string>
<!-- Accessibility text for the handle menu new window button [CHAR LIMIT=NONE] -->
<string name="new_window_text">New Window</string>
+ <!-- Accessibility text for the handle menu new window button [CHAR LIMIT=NONE] -->
+ <string name="manage_windows_text">Manage Windows</string>
<!-- Accessibility text for the handle menu close button [CHAR LIMIT=NONE] -->
<string name="close_text">Close</string>
<!-- Accessibility text for the handle menu close menu button [CHAR LIMIT=NONE] -->
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index 13c0e66..d061ae1 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -82,7 +82,7 @@
<item name="android:textColor">@color/tv_pip_edu_text</item>
</style>
- <style name="LetterboxDialog" parent="@android:style/Theme.Holo">
+ <style name="LetterboxDialog" parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">@color/letterbox_dialog_background</item>
@@ -90,7 +90,7 @@
<style name="RestartDialogTitleText">
<item name="android:textSize">24sp</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
<item name="android:lineSpacingExtra">8sp</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
</style>
@@ -102,23 +102,23 @@
<style name="RestartDialogBodyText" parent="RestartDialogBodyStyle">
<item name="android:letterSpacing">0.02</item>
- <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
<item name="android:lineSpacingExtra">6sp</item>
</style>
<style name="RestartDialogCheckboxText" parent="RestartDialogBodyStyle">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
<item name="android:lineSpacingExtra">6sp</item>
</style>
<style name="RestartDialogDismissButton" parent="RestartDialogBodyStyle">
<item name="android:lineSpacingExtra">2sp</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textColor">?androidprv:attr/materialColorPrimary</item>
</style>
<style name="RestartDialogConfirmButton" parent="RestartDialogBodyStyle">
<item name="android:lineSpacingExtra">2sp</item>
- <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnPrimary</item>
</style>
<style name="ReachabilityEduHandLayout" parent="Theme.AppCompat.Light">
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 341ca0e..dd86a1a 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -90,6 +90,19 @@
/** The maximum override density allowed for tasks inside the desktop. */
private static final int DESKTOP_DENSITY_MAX = 1000;
+ /** The number of [WindowDecorViewHost] instances to warm up on system start. */
+ private static final int WINDOW_DECOR_PRE_WARM_SIZE = 2;
+
+ /**
+ * Sysprop declaring whether to enters desktop mode by default when the windowing mode of the
+ * display's root TaskDisplayArea is set to WINDOWING_MODE_FREEFORM.
+ *
+ * <p>If it is not defined, then {@code R.integer.config_enterDesktopByDefaultOnFreeformDisplay}
+ * is used.
+ */
+ public static final String ENTER_DESKTOP_BY_DEFAULT_ON_FREEFORM_DISPLAY_SYS_PROP =
+ "persist.wm.debug.enter_desktop_by_default_on_freeform_display";
+
/**
* Sysprop declaring the maximum number of Tasks to show in Desktop Mode at any one time.
*
@@ -102,6 +115,14 @@
private static final String MAX_TASK_LIMIT_SYS_PROP = "persist.wm.debug.desktop_max_task_limit";
/**
+ * Sysprop declaring the number of [WindowDecorViewHost] instances to warm up on system start.
+ *
+ * <p>If it is not defined, then [WINDOW_DECOR_PRE_WARM_SIZE] is used.
+ */
+ private static final String WINDOW_DECOR_PRE_WARM_SIZE_SYS_PROP =
+ "persist.wm.debug.desktop_window_decor_pre_warm_size";
+
+ /**
* Return {@code true} if veiled resizing is active. If false, fluid resizing is used.
*/
public static boolean isVeiledResizeEnabled() {
@@ -141,6 +162,12 @@
context.getResources().getInteger(R.integer.config_maxDesktopWindowingActiveTasks));
}
+ /** The number of [WindowDecorViewHost] instances to warm up on system start. */
+ public static int getWindowDecorPreWarmSize() {
+ return SystemProperties.getInt(WINDOW_DECOR_PRE_WARM_SIZE_SYS_PROP,
+ WINDOW_DECOR_PRE_WARM_SIZE);
+ }
+
/**
* Return {@code true} if the current device supports desktop mode.
*/
@@ -206,6 +233,19 @@
return !enforceDeviceRestrictions() || isDesktopModeSupported(context);
}
+ /**
+ * Return {@code true} if a display should enter desktop mode by default when the windowing mode
+ * of the display's root [TaskDisplayArea] is set to WINDOWING_MODE_FREEFORM.
+ */
+ public static boolean enterDesktopByDefaultOnFreeformDisplay(@NonNull Context context) {
+ if (!Flags.enterDesktopByDefaultOnFreeformDisplays()) {
+ return false;
+ }
+ return SystemProperties.getBoolean(ENTER_DESKTOP_BY_DEFAULT_ON_FREEFORM_DISPLAY_SYS_PROP,
+ context.getResources().getBoolean(
+ R.bool.config_enterDesktopByDefaultOnFreeformDisplay));
+ }
+
/** Dumps DesktopModeStatus flags and configs. */
public static void dump(PrintWriter pw, String prefix, Context context) {
String innerPrefix = prefix + " ";
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
new file mode 100644
index 0000000..79becb0
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.shared.desktopmode
+import android.annotation.ColorInt
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.RoundRectShape
+import android.util.TypedValue
+import android.view.MotionEvent.ACTION_OUTSIDE
+import android.view.SurfaceView
+import android.view.ViewGroup.MarginLayoutParams
+import android.widget.LinearLayout
+import android.window.TaskSnapshot
+
+/**
+ * View for the All Windows menu option, used by both Desktop Windowing and Taskbar.
+ * The menu displays icons of all open instances of an app. Clicking the icon should launch
+ * the instance, which will be performed by the child class.
+ */
+abstract class ManageWindowsViewContainer(
+ val context: Context,
+ @ColorInt private val menuBackgroundColor: Int
+) {
+ lateinit var menuView: ManageWindowsView
+
+ /** Creates the base menu view and fills it with icon views. */
+ fun show(snapshotList: List<Pair<Int, TaskSnapshot>>,
+ onIconClickListener: ((Int) -> Unit),
+ onOutsideClickListener: (() -> Unit)): ManageWindowsView {
+ menuView = ManageWindowsView(context, menuBackgroundColor).apply {
+ this.onOutsideClickListener = onOutsideClickListener
+ this.onIconClickListener = onIconClickListener
+ this.generateIconViews(snapshotList)
+ }
+ addToContainer(menuView)
+ return menuView
+ }
+
+ /** Adds the menu view to the container responsible for displaying it. */
+ abstract fun addToContainer(menuView: ManageWindowsView)
+
+ /** Dispose of the menu, perform needed cleanup. */
+ abstract fun close()
+
+ companion object {
+ const val MANAGE_WINDOWS_MINIMUM_INSTANCES = 2
+ }
+
+ class ManageWindowsView(
+ private val context: Context,
+ menuBackgroundColor: Int
+ ) {
+ val rootView: LinearLayout = LinearLayout(context)
+ var menuHeight = 0
+ var menuWidth = 0
+ var onIconClickListener: ((Int) -> Unit)? = null
+ var onOutsideClickListener: (() -> Unit)? = null
+
+ init {
+ rootView.orientation = LinearLayout.VERTICAL
+ val menuBackground = ShapeDrawable()
+ val menuRadius = getDimensionPixelSize(MENU_RADIUS_DP)
+ menuBackground.shape = RoundRectShape(
+ FloatArray(8) { menuRadius },
+ null,
+ null
+ )
+ menuBackground.paint.color = menuBackgroundColor
+ rootView.background = menuBackground
+ rootView.elevation = getDimensionPixelSize(MENU_ELEVATION_DP)
+ rootView.setOnTouchListener { _, event ->
+ if (event.actionMasked == ACTION_OUTSIDE) {
+ onOutsideClickListener?.invoke()
+ }
+ return@setOnTouchListener true
+ }
+ }
+
+ private fun getDimensionPixelSize(sizeDp: Float): Float {
+ return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ sizeDp, context.resources.displayMetrics)
+ }
+
+ fun generateIconViews(
+ snapshotList: List<Pair<Int, TaskSnapshot>>
+ ) {
+ menuWidth = 0
+ menuHeight = 0
+ rootView.removeAllViews()
+ val instanceIconHeight = getDimensionPixelSize(ICON_HEIGHT_DP)
+ val instanceIconWidth = getDimensionPixelSize(ICON_WIDTH_DP)
+ val iconRadius = getDimensionPixelSize(ICON_RADIUS_DP)
+ val iconMargin = getDimensionPixelSize(ICON_MARGIN_DP)
+ var rowLayout: LinearLayout? = null
+ // Add each icon to the menu, adding a new row when needed.
+ for ((iconCount, taskInfoSnapshotPair) in snapshotList.withIndex()) {
+ val taskId = taskInfoSnapshotPair.first
+ val snapshot = taskInfoSnapshotPair.second
+ // Once a row is filled, make a new row and increase the menu height.
+ if (iconCount % MENU_MAX_ICONS_PER_ROW == 0) {
+ rowLayout = LinearLayout(context)
+ rowLayout.orientation = LinearLayout.HORIZONTAL
+ rootView.addView(rowLayout)
+ menuHeight += (instanceIconHeight + iconMargin).toInt()
+ }
+ val snapshotBitmap = Bitmap.wrapHardwareBuffer(
+ snapshot.hardwareBuffer,
+ snapshot.colorSpace
+ )
+ val scaledSnapshotBitmap = snapshotBitmap?.let {
+ Bitmap.createScaledBitmap(
+ it, instanceIconWidth.toInt(), instanceIconHeight.toInt(), true /* filter */
+ )
+ }
+ val appSnapshotButton = SurfaceView(context)
+ appSnapshotButton.cornerRadius = iconRadius
+ appSnapshotButton.setZOrderOnTop(true)
+ appSnapshotButton.setOnClickListener {
+ onIconClickListener?.invoke(taskId)
+ }
+ val lp = MarginLayoutParams(
+ instanceIconWidth.toInt(), instanceIconHeight.toInt()
+ )
+ lp.apply {
+ marginStart = iconMargin.toInt()
+ topMargin = iconMargin.toInt()
+ }
+ appSnapshotButton.layoutParams = lp
+ // If we haven't already reached one full row, increment width.
+ if (iconCount < MENU_MAX_ICONS_PER_ROW) {
+ menuWidth += (instanceIconWidth + iconMargin).toInt()
+ }
+ rowLayout?.addView(appSnapshotButton)
+ appSnapshotButton.requestLayout()
+ rowLayout?.post {
+ appSnapshotButton.holder.surface
+ .attachAndQueueBufferWithColorSpace(
+ scaledSnapshotBitmap?.hardwareBuffer,
+ scaledSnapshotBitmap?.colorSpace
+ )
+ }
+ }
+ // Add margin again for the right/bottom of the menu.
+ menuWidth += iconMargin.toInt()
+ menuHeight += iconMargin.toInt()
+ }
+
+ companion object {
+ private const val MENU_RADIUS_DP = 26f
+ private const val ICON_WIDTH_DP = 204f
+ private const val ICON_HEIGHT_DP = 127.5f
+ private const val ICON_RADIUS_DP = 16f
+ private const val ICON_MARGIN_DP = 16f
+ private const val MENU_ELEVATION_DP = 1f
+ private const val MENU_MAX_ICONS_PER_ROW = 3
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
index f02559f..df3a369 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "WMShellUnitTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "com.android.wm.shell.back"
- }
- ]
+ "name": "WMShellUnitTests_shell_back"
},
{
- "name": "CtsWindowManagerDeviceBackNavigation",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.server.wm.backnavigation.BackGestureInvokedTest"
- },
- {
- "include-filter": "android.server.wm.backnavigation.BackNavigationTests"
- },
- {
- "include-filter": "android.server.wm.backnavigation.OnBackInvokedCallbackGestureTest"
- }
- ]
+ "name": "CtsWindowManagerDeviceBackNavigation_com_android_wm_shell_back"
}
]
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index c545d73..d253736 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -2007,7 +2007,7 @@
@Override
public void selectionChanged(BubbleViewProvider selectedBubble) {
// Only need to update the layer view if we're currently expanded for selection changes.
- if (mLayerView != null && isStackExpanded()) {
+ if (mLayerView != null && mLayerView.isExpanded()) {
mLayerView.showExpandedView(selectedBubble);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 1c9c195..1367b7e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -186,6 +186,10 @@
if (expandedView == null) {
return;
}
+ if (mExpandedBubble != null && mIsExpanded && b.getKey().equals(mExpandedBubble.getKey())) {
+ // Already showing this bubble, skip animating
+ return;
+ }
if (mExpandedBubble != null && !b.getKey().equals(mExpandedBubble.getKey())) {
removeView(mExpandedView);
mExpandedView = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index f03daad..c4082d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -303,21 +303,29 @@
lastSurfacePosition);
} else {
if (!haveSameLeash(mImeSourceControl, imeSourceControl)) {
- applyVisibilityToLeash(imeSourceControl);
-
if (android.view.inputmethod.Flags.refactorInsetsController()) {
pendingImeStartAnimation = true;
+ // The starting point for the IME should be it's previous state
+ // (whether it is initiallyVisible or not)
+ updateImeVisibility(imeSourceControl.isInitiallyVisible());
}
+ applyVisibilityToLeash(imeSourceControl);
}
if (!mImeShowing) {
removeImeSurface(mDisplayId);
}
}
- } else if (!android.view.inputmethod.Flags.refactorInsetsController()
- && mAnimation != null) {
- // we don"t want to cancel the hide animation, when the control is lost, but
- // continue the bar to slide to the end (even without visible IME)
- mAnimation.cancel();
+ } else {
+ if (!android.view.inputmethod.Flags.refactorInsetsController()
+ && mAnimation != null) {
+ // we don't want to cancel the hide animation, when the control is lost, but
+ // continue the bar to slide to the end (even without visible IME)
+ mAnimation.cancel();
+ } else if (android.view.inputmethod.Flags.refactorInsetsController() && mImeShowing
+ && mAnimation == null) {
+ // There is no leash, so the IME cannot be in a showing state
+ updateImeVisibility(false);
+ }
}
// Make mImeSourceControl point to the new control before starting the animation.
@@ -341,7 +349,7 @@
if (android.view.inputmethod.Flags.refactorInsetsController()) {
if (pendingImeStartAnimation) {
- startAnimation(true, true /* forceRestart */);
+ startAnimation(mImeRequestedVisible, true /* forceRestart */);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 8c7dcf2..b151c8b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -116,6 +116,8 @@
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import com.android.wm.shell.windowdecor.viewhost.DefaultWindowDecorViewHostSupplier;
+import com.android.wm.shell.windowdecor.viewhost.PooledWindowDecorViewHostSupplier;
+import com.android.wm.shell.windowdecor.viewhost.ReusableWindowDecorViewHost;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
import dagger.Binds;
@@ -380,8 +382,19 @@
@WMSingleton
@Provides
static WindowDecorViewHostSupplier provideWindowDecorViewHostSupplier(
- @ShellMainThread @NonNull CoroutineScope mainScope) {
- return new DefaultWindowDecorViewHostSupplier(mainScope);
+ @NonNull Context context,
+ @ShellMainThread @NonNull CoroutineScope mainScope,
+ @NonNull ShellInit shellInit) {
+ if (DesktopModeStatus.canEnterDesktopMode(context)
+ && Flags.enableDesktopWindowingScvhCache()) {
+ final int maxPoolSize = DesktopModeStatus.getMaxTaskLimit(context);
+ final int preWarmSize = DesktopModeStatus.getWindowDecorPreWarmSize();
+ return new PooledWindowDecorViewHostSupplier(
+ context, mainScope, shellInit,
+ ReusableWindowDecorViewHost.DefaultFactory.INSTANCE, maxPoolSize, preWarmSize);
+ } else {
+ return new DefaultWindowDecorViewHostSupplier(mainScope);
+ }
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index c8ffe28..bd61722 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -162,7 +162,7 @@
fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float {
val appLetterboxWidth = taskInfo.appCompatTaskInfo.topActivityLetterboxAppWidth
val appLetterboxHeight = taskInfo.appCompatTaskInfo.topActivityLetterboxAppHeight
- if (taskInfo.appCompatTaskInfo.isTopActivityLetterboxed) {
+ if (taskInfo.appCompatTaskInfo.isTopActivityLetterboxed || !taskInfo.canChangeAspectRatio) {
return maxOf(appLetterboxWidth, appLetterboxHeight) /
minOf(appLetterboxWidth, appLetterboxHeight).toFloat()
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 1d16980..c74f4a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -303,6 +303,15 @@
private fun getSplitFocusedTask(task1: RunningTaskInfo, task2: RunningTaskInfo) =
if (task1.taskId == task2.parentTaskId) task2 else task1
+ private fun isFreeformDisplay(displayId: Int): Boolean {
+ val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
+ requireNotNull(tdaInfo) {
+ "This method can only be called with the ID of a display having non-null DisplayArea."
+ }
+ val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode
+ return tdaWindowingMode == WINDOWING_MODE_FREEFORM
+ }
+
/** Moves task to desktop mode if task is running, else launches it in desktop mode. */
fun moveTaskToDesktop(
taskId: Int,
@@ -1077,45 +1086,47 @@
request.triggerTask != null
}
+ /** Open an existing instance of an app. */
+ fun openInstance(
+ callingTask: RunningTaskInfo,
+ requestedTaskId: Int
+ ) {
+ val wct = WindowContainerTransaction()
+ val options = createNewWindowOptions(callingTask)
+ if (options.launchWindowingMode == WINDOWING_MODE_FREEFORM) {
+ wct.startTask(requestedTaskId, options.toBundle())
+ transitions.startTransition(TRANSIT_OPEN, wct, null)
+ } else {
+ val splitPosition = splitScreenController.determineNewInstancePosition(callingTask)
+ splitScreenController.startTask(requestedTaskId, splitPosition,
+ options.toBundle(), null /* hideTaskToken */)
+ }
+ }
+
+ /** Create an Intent to open a new window of a task. */
fun openNewWindow(
- taskInfo: RunningTaskInfo
+ callingTaskInfo: RunningTaskInfo
) {
// TODO(b/337915660): Add a transition handler for these; animations
// need updates in some cases.
- val newTaskWindowingMode = when {
- taskInfo.isFreeform -> {
- WINDOWING_MODE_FREEFORM
- }
- taskInfo.isFullscreen || taskInfo.isMultiWindow -> {
- WINDOWING_MODE_MULTI_WINDOW
- }
- else -> {
- error("Invalid windowing mode: ${taskInfo.windowingMode}")
- }
- }
-
- val baseActivity = taskInfo.baseActivity ?: return
+ val baseActivity = callingTaskInfo.baseActivity ?: return
val fillIn: Intent = context.packageManager
.getLaunchIntentForPackage(
baseActivity.packageName
) ?: return
fillIn
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
- val options =
- ActivityOptions.makeBasic().apply {
- launchWindowingMode = newTaskWindowingMode
- pendingIntentBackgroundActivityStartMode =
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
- }
val launchIntent = PendingIntent.getActivity(
context,
/* requestCode= */ 0,
fillIn,
PendingIntent.FLAG_IMMUTABLE
)
- when (newTaskWindowingMode) {
+ val options = createNewWindowOptions(callingTaskInfo)
+ when (options.launchWindowingMode) {
WINDOWING_MODE_MULTI_WINDOW -> {
- val splitPosition = splitScreenController.determineNewInstancePosition(taskInfo)
+ val splitPosition = splitScreenController
+ .determineNewInstancePosition(callingTaskInfo)
splitScreenController.startIntent(
launchIntent, context.userId, fillIn, splitPosition,
options.toBundle(), null /* hideTaskToken */
@@ -1130,6 +1141,25 @@
}
}
+ private fun createNewWindowOptions(callingTask: RunningTaskInfo): ActivityOptions {
+ val newTaskWindowingMode = when {
+ callingTask.isFreeform -> {
+ WINDOWING_MODE_FREEFORM
+ }
+ callingTask.isFullscreen || callingTask.isMultiWindow -> {
+ WINDOWING_MODE_MULTI_WINDOW
+ }
+ else -> {
+ error("Invalid windowing mode: ${callingTask.windowingMode}")
+ }
+ }
+ return ActivityOptions.makeBasic().apply {
+ launchWindowingMode = newTaskWindowingMode
+ pendingIntentBackgroundActivityStartMode =
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
+ }
+ }
+
/**
* Handles the case where a freeform task is launched from recents.
*
@@ -1199,7 +1229,9 @@
transition: IBinder
): WindowContainerTransaction? {
logV("handleFullscreenTaskLaunch")
- if (isDesktopModeShowing(task.displayId)) {
+ val forceEnterDesktop = DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context) &&
+ isFreeformDisplay(task.displayId)
+ if (isDesktopModeShowing(task.displayId) || forceEnterDesktop) {
logD("Switch fullscreen task to freeform on transition: taskId=%d", task.taskId)
return WindowContainerTransaction().also { wct ->
addMoveToDesktopChanges(wct, task)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index d72ec90..dfc5ab3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -629,15 +629,20 @@
finishTransaction: SurfaceControl.Transaction?
) {
val state = transitionState ?: return
- if (aborted && state.startTransitionToken == transition) {
+ if (!aborted) {
+ return
+ }
+ if (state.startTransitionToken == transition) {
ProtoLog.v(
ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
"DragToDesktop: onTransitionConsumed() start transition aborted"
)
state.startAborted = true
- // Cancel CUJ interaction if the transition is aborted.
+ // The start-transition (DRAG_HOLD) is aborted, cancel its jank interaction.
interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
} else if (state.cancelTransitionToken != transition) {
+ // This transition being aborted is neither the start, nor the cancel transition, so
+ // it must be the finish transition (DRAG_RELEASE); cancel its jank interaction.
interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index cf02fb5..22e8dc1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -26,7 +26,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
@@ -247,9 +246,8 @@
R.layout.global_drop_target, null);
rootView.setOnDragListener(this);
rootView.setVisibility(View.INVISIBLE);
- DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
- rootView.addView(dragLayout,
- new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ DragLayoutProvider dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
+ dragLayout.addDraggingView(rootView);
try {
wm.addView(rootView, layoutParams);
addDisplayDropTarget(displayId, context, wm, rootView, dragLayout);
@@ -261,7 +259,7 @@
@VisibleForTesting
void addDisplayDropTarget(int displayId, Context context, WindowManager wm,
- FrameLayout rootView, DragLayout dragLayout) {
+ FrameLayout rootView, DragLayoutProvider dragLayout) {
mDisplayDropTargets.put(displayId,
new PerDisplay(displayId, context, wm, rootView, dragLayout));
}
@@ -564,7 +562,7 @@
final Context context;
final WindowManager wm;
final FrameLayout rootView;
- final DragLayout dragLayout;
+ final DragLayoutProvider dragLayout;
// Tracks whether the window has fully drawn since it was last made visible
boolean hasDrawn;
@@ -575,7 +573,7 @@
// The active drag session
DragSession dragSession;
- PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
+ PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayoutProvider dl) {
displayId = dispId;
context = c;
wm = w;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 3fecbe7..dfa2437 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -23,10 +23,10 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -47,6 +47,7 @@
import android.graphics.drawable.Drawable;
import android.view.DragEvent;
import android.view.SurfaceControl;
+import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowInsets.Type;
@@ -66,13 +67,13 @@
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter;
-import java.util.ArrayList;
+import java.util.List;
/**
* Coordinates the visible drop targets for the current drag within a single display.
*/
public class DragLayout extends LinearLayout
- implements ViewTreeObserver.OnComputeInternalInsetsListener {
+ implements ViewTreeObserver.OnComputeInternalInsetsListener, DragLayoutProvider {
// While dragging the status bar is hidden.
private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
@@ -80,7 +81,7 @@
| StatusBarManager.DISABLE_CLOCK
| StatusBarManager.DISABLE_SYSTEM_INFO;
- private final DragAndDropPolicy mPolicy;
+ private final DropTarget mPolicy;
private final SplitScreenController mSplitScreenController;
private final IconProvider mIconProvider;
private final StatusBarManager mStatusBarManager;
@@ -91,7 +92,7 @@
// Whether the device is currently in left/right split mode
private boolean mIsLeftRightSplit;
- private DragAndDropPolicy.Target mCurrentTarget = null;
+ private SplitDragPolicy.Target mCurrentTarget = null;
private DropZoneView mDropZoneView1;
private DropZoneView mDropZoneView2;
@@ -113,7 +114,7 @@
super(context);
mSplitScreenController = splitScreenController;
mIconProvider = iconProvider;
- mPolicy = new DragAndDropPolicy(context, splitScreenController);
+ mPolicy = new SplitDragPolicy(context, splitScreenController);
mStatusBarManager = context.getSystemService(StatusBarManager.class);
mLastConfiguration.setTo(context.getResources().getConfiguration());
@@ -387,6 +388,13 @@
recomputeDropTargets();
}
+ @NonNull
+ @Override
+ public void addDraggingView(ViewGroup rootView) {
+ // TODO(b/349828130) We need to separate out view + logic here
+ rootView.addView(this, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ }
+
/**
* Recalculates the drop targets based on the current policy.
*/
@@ -394,9 +402,9 @@
if (!mIsShowing) {
return;
}
- final ArrayList<DragAndDropPolicy.Target> targets = mPolicy.getTargets(mInsets);
+ final List<SplitDragPolicy.Target> targets = mPolicy.getTargets(mInsets);
for (int i = 0; i < targets.size(); i++) {
- final DragAndDropPolicy.Target target = targets.get(i);
+ final SplitDragPolicy.Target target = targets.get(i);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Add target: %s", target);
// Inset the draw region by a little bit
target.drawRegion.inset(mDisplayMargin, mDisplayMargin);
@@ -419,7 +427,7 @@
}
// Find containing region, if the same as mCurrentRegion, then skip, otherwise, animate the
// visibility of the current region
- DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
+ SplitDragPolicy.Target target = mPolicy.getTargetAtLocation(x, y);
if (mCurrentTarget != target) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
if (target == null) {
@@ -493,7 +501,7 @@
mHasDropped = true;
// Process the drop
- mPolicy.handleDrop(mCurrentTarget, hideTaskToken);
+ mPolicy.onDropped(mCurrentTarget, hideTaskToken);
// Start animating the drop UI out with the drag surface
hide(event, dropCompleteCallback);
@@ -576,7 +584,7 @@
}
}
- private void animateHighlight(DragAndDropPolicy.Target target) {
+ private void animateHighlight(SplitDragPolicy.Target target) {
if (target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP) {
mDropZoneView1.setShowingHighlight(true);
mDropZoneView2.setShowingHighlight(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt
new file mode 100644
index 0000000..3d40824
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayoutProvider.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.draganddrop
+
+import android.content.res.Configuration
+import android.view.DragEvent
+import android.view.SurfaceControl
+import android.view.ViewGroup
+import android.window.WindowContainerToken
+import com.android.internal.logging.InstanceId
+import java.io.PrintWriter
+
+/** Interface to be implemented by any controllers providing a layout for DragAndDrop in Shell */
+interface DragLayoutProvider {
+ /**
+ * Updates the drag layout based on the given drag session.
+ */
+ fun updateSession(session: DragSession)
+ /**
+ * Called when a new drag is started.
+ */
+ fun prepare(session: DragSession, loggerSessionId: InstanceId?)
+
+ /**
+ * Shows the drag layout.
+ */
+ fun show()
+
+ /**
+ * Updates the visible drop target as the user drags.
+ */
+ fun update(event: DragEvent?)
+
+ /**
+ * Hides the drag layout and animates out the visible drop targets.
+ */
+ fun hide(event: DragEvent?, hideCompleteCallback: Runnable?)
+
+ /**
+ * Whether target has already been dropped or not
+ */
+ fun hasDropped(): Boolean
+
+ /**
+ * Handles the drop onto a target and animates out the visible drop targets.
+ */
+ fun drop(
+ event: DragEvent?, dragSurface: SurfaceControl,
+ hideTaskToken: WindowContainerToken?, dropCompleteCallback: Runnable?
+ ): Boolean
+
+ /**
+ * Dumps information about this drag layout.
+ */
+ fun dump(pw: PrintWriter, prefix: String?)
+
+ /**
+ * @return a View which will be added to the global root view for drag and drop
+ */
+ fun addDraggingView(viewGroup: ViewGroup)
+
+ /**
+ * Called when the configuration changes.
+ */
+ fun onConfigChanged(newConfig: Configuration?)
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
new file mode 100644
index 0000000..122a105
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropTarget.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.draganddrop
+
+import android.graphics.Insets
+import android.window.WindowContainerToken
+import com.android.internal.logging.InstanceId
+
+/**
+ * Interface to be implemented by classes which want to provide drop targets
+ * for DragAndDrop in Shell
+ */
+interface DropTarget {
+ // TODO(b/349828130) Delete after flexible split launches
+ /**
+ * Called at the start of a Drag, before input events are processed.
+ */
+ fun start(dragSession: DragSession, logSessionId: InstanceId)
+ /**
+ * @return [SplitDragPolicy.Target] corresponding to the given coords in display bounds.
+ */
+ fun getTargetAtLocation(x: Int, y: Int) : SplitDragPolicy.Target
+ /**
+ * @return total number of drop targets for the current drag session.
+ */
+ fun getNumTargets() : Int
+ // TODO(b/349828130)
+
+ /**
+ * @return [List<SplitDragPolicy.Target>] to show for the current drag session.
+ */
+ fun getTargets(insets: Insets) : List<SplitDragPolicy.Target>
+ /**
+ * Called when user is hovering Drag object over the given Target
+ */
+ fun onHoveringOver(target: SplitDragPolicy.Target) {}
+ /**
+ * Called when the user has dropped the provided target (need not be the same target as
+ * [onHoveringOver])
+ */
+ fun onDropped(target: SplitDragPolicy.Target, hideTaskToken: WindowContainerToken)
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
similarity index 93%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
index 6fec0c1..2a19d65 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/SplitDragPolicy.java
@@ -32,11 +32,11 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.shared.draganddrop.DragAndDropConstants.EXTRA_DISALLOW_HIT_REGION;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -80,9 +80,9 @@
/**
* The policy for handling drag and drop operations to shell.
*/
-public class DragAndDropPolicy {
+public class SplitDragPolicy implements DropTarget {
- private static final String TAG = DragAndDropPolicy.class.getSimpleName();
+ private static final String TAG = SplitDragPolicy.class.getSimpleName();
private final Context mContext;
// Used only for launching a fullscreen task (or as a fallback if there is no split starter)
@@ -90,18 +90,18 @@
// Used for launching tasks into splitscreen
private final Starter mSplitscreenStarter;
private final SplitScreenController mSplitScreen;
- private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
+ private final ArrayList<SplitDragPolicy.Target> mTargets = new ArrayList<>();
private final RectF mDisallowHitRegion = new RectF();
private InstanceId mLoggerSessionId;
private DragSession mSession;
- public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
+ public SplitDragPolicy(Context context, SplitScreenController splitScreen) {
this(context, splitScreen, new DefaultStarter(context));
}
@VisibleForTesting
- DragAndDropPolicy(Context context, SplitScreenController splitScreen,
+ SplitDragPolicy(Context context, SplitScreenController splitScreen,
Starter fullscreenStarter) {
mContext = context;
mSplitScreen = splitScreen;
@@ -112,7 +112,7 @@
/**
* Starts a new drag session with the given initial drag data.
*/
- void start(DragSession session, InstanceId loggerSessionId) {
+ public void start(DragSession session, InstanceId loggerSessionId) {
mLoggerSessionId = loggerSessionId;
mSession = session;
RectF disallowHitRegion = mSession.appData != null
@@ -128,7 +128,8 @@
/**
* Returns the number of targets.
*/
- int getNumTargets() {
+ @Override
+ public int getNumTargets() {
return mTargets.size();
}
@@ -136,7 +137,8 @@
* Returns the target's regions based on the current state of the device and display.
*/
@NonNull
- ArrayList<Target> getTargets(Insets insets) {
+ @Override
+ public ArrayList<Target> getTargets(@NonNull Insets insets) {
mTargets.clear();
if (mSession == null) {
// Return early if this isn't an app drag
@@ -222,12 +224,12 @@
* Returns the target at the given position based on the targets previously calculated.
*/
@Nullable
- Target getTargetAtLocation(int x, int y) {
+ public Target getTargetAtLocation(int x, int y) {
if (mDisallowHitRegion.contains(x, y)) {
return null;
}
for (int i = mTargets.size() - 1; i >= 0; i--) {
- DragAndDropPolicy.Target t = mTargets.get(i);
+ SplitDragPolicy.Target t = mTargets.get(i);
if (t.hitRegion.contains(x, y)) {
return t;
}
@@ -241,7 +243,7 @@
* container transaction if possible.
*/
@VisibleForTesting
- void handleDrop(Target target, @Nullable WindowContainerToken hideTaskToken) {
+ public void onDropped(Target target, @Nullable WindowContainerToken hideTaskToken) {
if (target == null || !mTargets.contains(target)) {
return;
}
@@ -419,8 +421,9 @@
/**
* Represents a drop target.
+ * TODO(b/349828130): Move this into {@link DropTarget}
*/
- static class Target {
+ public static class Target {
static final int TYPE_FULLSCREEN = 0;
static final int TYPE_SPLIT_LEFT = 1;
static final int TYPE_SPLIT_TOP = 2;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index ab222c9..b4e0329 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -2033,7 +2033,10 @@
tx.apply();
}
- private void cancelCurrentAnimator() {
+ /**
+ * Cancels the currently running animator if there is one and removes an overlay if present.
+ */
+ public void cancelCurrentAnimator() {
final PipAnimationController.PipTransitionAnimator<?> animator =
mPipAnimationController.getCurrentAnimator();
// remove any overlays if present
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 755e958..deb7691 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -324,7 +324,7 @@
return;
}
onDisplayChanged(mDisplayController.getDisplayLayout(displayId),
- false /* saveRestoreSnapFraction */);
+ true /* saveRestoreSnapFraction */);
}
@Override
@@ -652,9 +652,11 @@
// there's a keyguard present
return;
}
- onDisplayChangedUncheck(mDisplayController
- .getDisplayLayout(mPipDisplayLayoutState.getDisplayId()),
- false /* saveRestoreSnapFraction */);
+ mMainExecutor.executeDelayed(() -> {
+ onDisplayChangedUncheck(mDisplayController.getDisplayLayout(
+ mPipDisplayLayoutState.getDisplayId()),
+ false /* saveRestoreSnapFraction */);
+ }, PIP_KEEP_CLEAR_AREAS_DELAY);
}
});
@@ -800,7 +802,7 @@
}
};
- if (mPipTaskOrganizer.isInPip() && saveRestoreSnapFraction) {
+ if (mPipTransitionState.hasEnteredPip() && saveRestoreSnapFraction) {
mMenuController.attachPipMenuView();
// Calculate the snap fraction of the current stack along the old movement bounds
final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 793e2aa..87b661d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -92,7 +92,7 @@
import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.draganddrop.DragAndDropController;
-import com.android.wm.shell.draganddrop.DragAndDropPolicy;
+import com.android.wm.shell.draganddrop.SplitDragPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.shared.TransactionPool;
@@ -121,7 +121,7 @@
* @see StageCoordinator
*/
// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
-public class SplitScreenController implements DragAndDropPolicy.Starter,
+public class SplitScreenController implements SplitDragPolicy.Starter,
RemoteCallable<SplitScreenController>, KeyguardChangeListener {
private static final String TAG = SplitScreenController.class.getSimpleName();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index f40e0ba..1573291 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -358,9 +358,12 @@
if (mode == TRANSIT_CHANGE && change.hasFlags(FLAG_IS_DISPLAY)) {
if (info.getType() == TRANSIT_CHANGE) {
- final int anim = getRotationAnimationHint(change, info, mDisplayController);
+ int anim = getRotationAnimationHint(change, info, mDisplayController);
isSeamlessDisplayChange = anim == ROTATION_ANIMATION_SEAMLESS;
if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) {
+ if (wallpaperTransit != WALLPAPER_TRANSITION_NONE) {
+ anim |= ScreenRotationAnimation.ANIMATION_HINT_HAS_WALLPAPER;
+ }
startRotationAnimation(startTransaction, change, info, anim, animations,
onAnimFinish);
isDisplayRotationAnimationStarted = true;
@@ -826,24 +829,26 @@
@NonNull Runnable finishCallback, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
@Nullable Rect clipRect, boolean isActivity) {
+ final DefaultAnimationAdapter adapter = new DefaultAnimationAdapter(anim, leash,
+ position, clipRect, cornerRadius, isActivity);
+ buildSurfaceAnimation(animations, anim, finishCallback, pool, mainExecutor, adapter);
+ }
+
+ /** Builds an animator for the surface and adds it to the `animations` list. */
+ static void buildSurfaceAnimation(@NonNull ArrayList<Animator> animations,
+ @NonNull Animation anim, @NonNull Runnable finishCallback,
+ @NonNull TransactionPool pool, @NonNull ShellExecutor mainExecutor,
+ @NonNull AnimationAdapter updateListener) {
final SurfaceControl.Transaction transaction = pool.acquire();
+ updateListener.setTransaction(transaction);
final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
- final Transformation transformation = new Transformation();
- final float[] matrix = new float[9];
// Animation length is already expected to be scaled.
va.overrideDurationScale(1.0f);
va.setDuration(anim.computeDurationHint());
- final ValueAnimator.AnimatorUpdateListener updateListener = animation -> {
- final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
-
- applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix,
- position, cornerRadius, clipRect, isActivity);
- };
va.addUpdateListener(updateListener);
final Runnable finisher = () -> {
- applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix,
- position, cornerRadius, clipRect, isActivity);
+ updateListener.onAnimationUpdate(va);
pool.release(transaction);
mainExecutor.execute(() -> {
@@ -1007,37 +1012,88 @@
|| animType == ANIM_FROM_STYLE;
}
- private static void applyTransformation(long time, SurfaceControl.Transaction t,
- SurfaceControl leash, Animation anim, Transformation tmpTransformation, float[] matrix,
- Point position, float cornerRadius, @Nullable Rect immutableClipRect,
- boolean isActivity) {
- tmpTransformation.clear();
- anim.getTransformation(time, tmpTransformation);
- if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
- && anim.getExtensionEdges() != 0x0 && isActivity) {
- t.setEdgeExtensionEffect(leash, anim.getExtensionEdges());
- }
- if (position != null) {
- tmpTransformation.getMatrix().postTranslate(position.x, position.y);
- }
- t.setMatrix(leash, tmpTransformation.getMatrix(), matrix);
- t.setAlpha(leash, tmpTransformation.getAlpha());
+ /** The animation adapter for buildSurfaceAnimation. */
+ abstract static class AnimationAdapter implements ValueAnimator.AnimatorUpdateListener {
+ @NonNull final SurfaceControl mLeash;
+ @NonNull SurfaceControl.Transaction mTransaction;
+ private Choreographer mChoreographer;
- final Rect clipRect = immutableClipRect == null ? null : new Rect(immutableClipRect);
- Insets extensionInsets = Insets.min(tmpTransformation.getInsets(), Insets.NONE);
- if (!extensionInsets.equals(Insets.NONE) && clipRect != null && !clipRect.isEmpty()) {
- // Clip out any overflowing edge extension
- clipRect.inset(extensionInsets);
- t.setCrop(leash, clipRect);
+ AnimationAdapter(@NonNull SurfaceControl leash) {
+ mLeash = leash;
}
- if (anim.hasRoundedCorners() && cornerRadius > 0 && clipRect != null) {
- // We can only apply rounded corner if a crop is set
- t.setCrop(leash, clipRect);
- t.setCornerRadius(leash, cornerRadius);
+ void setTransaction(@NonNull SurfaceControl.Transaction transaction) {
+ mTransaction = transaction;
}
- t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
- t.apply();
+ @Override
+ public void onAnimationUpdate(@NonNull ValueAnimator animator) {
+ applyTransformation(animator);
+ if (mChoreographer == null) {
+ mChoreographer = Choreographer.getInstance();
+ }
+ mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
+ mTransaction.apply();
+ }
+
+ abstract void applyTransformation(@NonNull ValueAnimator animator);
+ }
+
+ private static class DefaultAnimationAdapter extends AnimationAdapter {
+ final Transformation mTransformation = new Transformation();
+ final float[] mMatrix = new float[9];
+ @NonNull final Animation mAnim;
+ @Nullable final Point mPosition;
+ @Nullable final Rect mClipRect;
+ final float mCornerRadius;
+ final boolean mIsActivity;
+
+ DefaultAnimationAdapter(@NonNull Animation anim, @NonNull SurfaceControl leash,
+ @Nullable Point position, @Nullable Rect clipRect, float cornerRadius,
+ boolean isActivity) {
+ super(leash);
+ mAnim = anim;
+ mPosition = (position != null && (position.x != 0 || position.y != 0))
+ ? position : null;
+ mClipRect = (clipRect != null && !clipRect.isEmpty()) ? clipRect : null;
+ mCornerRadius = cornerRadius;
+ mIsActivity = isActivity;
+ }
+
+ @Override
+ void applyTransformation(@NonNull ValueAnimator animator) {
+ final long currentPlayTime = Math.min(animator.getDuration(),
+ animator.getCurrentPlayTime());
+ final Transformation transformation = mTransformation;
+ final SurfaceControl.Transaction t = mTransaction;
+ final SurfaceControl leash = mLeash;
+ transformation.clear();
+ mAnim.getTransformation(currentPlayTime, transformation);
+ if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
+ && mIsActivity && mAnim.getExtensionEdges() != 0) {
+ t.setEdgeExtensionEffect(leash, mAnim.getExtensionEdges());
+ }
+ if (mPosition != null) {
+ transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
+ }
+ t.setMatrix(leash, transformation.getMatrix(), mMatrix);
+ t.setAlpha(leash, transformation.getAlpha());
+
+ if (mClipRect != null) {
+ Rect clipRect = mClipRect;
+ final Insets extensionInsets = Insets.min(transformation.getInsets(), Insets.NONE);
+ if (!extensionInsets.equals(Insets.NONE)) {
+ // Clip out any overflowing edge extension.
+ clipRect = new Rect(mClipRect);
+ clipRect.inset(extensionInsets);
+ t.setCrop(leash, clipRect);
+ }
+ if (mCornerRadius > 0 && mAnim.hasRoundedCorners()) {
+ // Rounded corner can only be applied if a crop is set.
+ t.setCrop(leash, clipRect);
+ t.setCornerRadius(leash, mCornerRadius);
+ }
+ }
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index 6013a1e..dec28fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -16,7 +16,7 @@
package com.android.wm.shell.transition;
-import static com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary;
+import static com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -257,7 +257,7 @@
@Override
public Transitions.TransitionHandler getHandlerForTakeover(
@NonNull IBinder transition, @NonNull TransitionInfo info) {
- if (!returnAnimationFrameworkLibrary()) {
+ if (!returnAnimationFrameworkLongLived()) {
return null;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index 5802e2c..b9d11a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -25,12 +25,9 @@
import static com.android.wm.shell.transition.Transitions.TAG;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.Context;
-import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
@@ -38,6 +35,7 @@
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
+import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.window.ScreenCapture;
@@ -74,6 +72,9 @@
*/
class ScreenRotationAnimation {
static final int MAX_ANIMATION_DURATION = 10 * 1000;
+ static final int ANIMATION_HINT_HAS_WALLPAPER = 1 << 8;
+ /** It must cover all WindowManager#ROTATION_ANIMATION_*. */
+ private static final int ANIMATION_TYPE_MASK = 0xff;
private final Context mContext;
private final TransactionPool mTransactionPool;
@@ -81,7 +82,7 @@
/** The leash of the changing window container. */
private final SurfaceControl mSurfaceControl;
- private final int mAnimHint;
+ private final int mAnimType;
private final int mStartWidth;
private final int mStartHeight;
private final int mEndWidth;
@@ -98,6 +99,12 @@
private SurfaceControl mBackColorSurface;
/** The leash using to animate screenshot layer. */
private final SurfaceControl mAnimLeash;
+ /**
+ * The container with background color for {@link #mSurfaceControl}. It is only created if
+ * {@link #mSurfaceControl} may be translucent. E.g. visible wallpaper with alpha < 1 (dimmed).
+ * That prevents flickering of alpha blending.
+ */
+ private SurfaceControl mBackEffectSurface;
// The current active animation to move from the old to the new rotated
// state. Which animation is run here will depend on the old and new
@@ -115,7 +122,7 @@
Transaction t, TransitionInfo.Change change, SurfaceControl rootLeash, int animHint) {
mContext = context;
mTransactionPool = pool;
- mAnimHint = animHint;
+ mAnimType = animHint & ANIMATION_TYPE_MASK;
mSurfaceControl = change.getLeash();
mStartWidth = change.getStartAbsBounds().width();
@@ -170,11 +177,20 @@
}
hardwareBuffer.close();
}
+ if ((animHint & ANIMATION_HINT_HAS_WALLPAPER) != 0) {
+ mBackEffectSurface = new SurfaceControl.Builder()
+ .setCallsite("ShellRotationAnimation").setParent(rootLeash)
+ .setEffectLayer().setOpaque(true).setName("BackEffect").build();
+ t.reparent(mSurfaceControl, mBackEffectSurface)
+ .setColor(mBackEffectSurface,
+ new float[] {mStartLuma, mStartLuma, mStartLuma})
+ .show(mBackEffectSurface);
+ }
t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
t.show(mAnimLeash);
// Crop the real content in case it contains a larger child layer, e.g. wallpaper.
- t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));
+ t.setCrop(getEnterSurface(), new Rect(0, 0, mEndWidth, mEndHeight));
if (!isCustomRotate()) {
mBackColorSurface = new SurfaceControl.Builder()
@@ -199,7 +215,12 @@
}
private boolean isCustomRotate() {
- return mAnimHint == ROTATION_ANIMATION_CROSSFADE || mAnimHint == ROTATION_ANIMATION_JUMPCUT;
+ return mAnimType == ROTATION_ANIMATION_CROSSFADE || mAnimType == ROTATION_ANIMATION_JUMPCUT;
+ }
+
+ /** Returns the surface which contains the real content to animate enter. */
+ private SurfaceControl getEnterSurface() {
+ return mBackEffectSurface != null ? mBackEffectSurface : mSurfaceControl;
}
private void setScreenshotTransform(SurfaceControl.Transaction t) {
@@ -260,7 +281,7 @@
final boolean customRotate = isCustomRotate();
if (customRotate) {
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
- mAnimHint == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit
+ mAnimType == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit
: R.anim.rotation_animation_xfade_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.rotation_animation_enter);
@@ -314,7 +335,11 @@
} else {
startDisplayRotation(animations, finishCallback, mainExecutor);
startScreenshotRotationAnimation(animations, finishCallback, mainExecutor);
- //startColorAnimation(mTransaction, animationScale);
+ if (mBackEffectSurface != null && mStartLuma > 0.1f) {
+ // Animate from the color of background to black for smooth alpha blending.
+ buildLumaAnimation(animations, mStartLuma, 0f /* endLuma */, mBackEffectSurface,
+ animationScale, finishCallback, mainExecutor);
+ }
}
return true;
@@ -322,7 +347,7 @@
private void startDisplayRotation(@NonNull ArrayList<Animator> animations,
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
- buildSurfaceAnimation(animations, mRotateEnterAnimation, mSurfaceControl, finishCallback,
+ buildSurfaceAnimation(animations, mRotateEnterAnimation, getEnterSurface(), finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
null /* clipRect */, false /* isActivity */);
}
@@ -341,40 +366,17 @@
null /* clipRect */, false /* isActivity */);
}
- private void startColorAnimation(float animationScale, @NonNull ShellExecutor animExecutor) {
- int colorTransitionMs = mContext.getResources().getInteger(
- R.integer.config_screen_rotation_color_transition);
- final float[] rgbTmpFloat = new float[3];
- final int startColor = Color.rgb(mStartLuma, mStartLuma, mStartLuma);
- final int endColor = Color.rgb(mEndLuma, mEndLuma, mEndLuma);
- final long duration = colorTransitionMs * (long) animationScale;
- final Transaction t = mTransactionPool.acquire();
-
- final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
- // Animation length is already expected to be scaled.
- va.overrideDurationScale(1.0f);
- va.setDuration(duration);
- va.addUpdateListener(animation -> {
- final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
- final float fraction = currentPlayTime / va.getDuration();
- applyColor(startColor, endColor, rgbTmpFloat, fraction, mBackColorSurface, t);
- });
- va.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- applyColor(startColor, endColor, rgbTmpFloat, 1f /* fraction */, mBackColorSurface,
- t);
- mTransactionPool.release(t);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- applyColor(startColor, endColor, rgbTmpFloat, 1f /* fraction */, mBackColorSurface,
- t);
- mTransactionPool.release(t);
- }
- });
- animExecutor.execute(va::start);
+ private void buildLumaAnimation(@NonNull ArrayList<Animator> animations,
+ float startLuma, float endLuma, SurfaceControl surface, float animationScale,
+ @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
+ final long durationMillis = (long) (mContext.getResources().getInteger(
+ R.integer.config_screen_rotation_color_transition) * animationScale);
+ final LumaAnimation animation = new LumaAnimation(durationMillis);
+ // Align the end with the enter animation.
+ animation.setStartOffset(mRotateEnterAnimation.getDuration() - durationMillis);
+ final LumaAnimationAdapter adapter = new LumaAnimationAdapter(surface, startLuma, endLuma);
+ buildSurfaceAnimation(animations, animation, finishCallback, mTransactionPool,
+ mainExecutor, adapter);
}
public void kill() {
@@ -389,21 +391,47 @@
if (mBackColorSurface != null && mBackColorSurface.isValid()) {
t.remove(mBackColorSurface);
}
+ if (mBackEffectSurface != null && mBackEffectSurface.isValid()) {
+ t.remove(mBackEffectSurface);
+ }
t.apply();
mTransactionPool.release(t);
}
- private static void applyColor(int startColor, int endColor, float[] rgbFloat,
- float fraction, SurfaceControl surface, SurfaceControl.Transaction t) {
- final int color = (Integer) ArgbEvaluator.getInstance().evaluate(fraction, startColor,
- endColor);
- Color middleColor = Color.valueOf(color);
- rgbFloat[0] = middleColor.red();
- rgbFloat[1] = middleColor.green();
- rgbFloat[2] = middleColor.blue();
- if (surface.isValid()) {
- t.setColor(surface, rgbFloat);
+ /** A no-op wrapper to provide animation duration. */
+ private static class LumaAnimation extends Animation {
+ LumaAnimation(long durationMillis) {
+ setDuration(durationMillis);
}
- t.apply();
+ }
+
+ private static class LumaAnimationAdapter extends DefaultTransitionHandler.AnimationAdapter {
+ final float[] mColorArray = new float[3];
+ final float mStartLuma;
+ final float mEndLuma;
+ final AccelerateInterpolator mInterpolation;
+
+ LumaAnimationAdapter(@NonNull SurfaceControl leash, float startLuma, float endLuma) {
+ super(leash);
+ mStartLuma = startLuma;
+ mEndLuma = endLuma;
+ // Make the initial progress color lighter if the background is light. That avoids
+ // darker content when fading into the entering surface.
+ final float factor = Math.min(3f, (Math.max(0.5f, mStartLuma) - 0.5f) * 10);
+ Slog.d(TAG, "Luma=" + mStartLuma + " factor=" + factor);
+ mInterpolation = factor > 0.5f ? new AccelerateInterpolator(factor) : null;
+ }
+
+ @Override
+ void applyTransformation(ValueAnimator animator) {
+ final float fraction = mInterpolation != null
+ ? mInterpolation.getInterpolation(animator.getAnimatedFraction())
+ : animator.getAnimatedFraction();
+ final float luma = mStartLuma + fraction * (mEndLuma - mStartLuma);
+ mColorArray[0] = luma;
+ mColorArray[1] = luma;
+ mColorArray[2] = luma;
+ mTransaction.setColor(mLeash, mColorArray);
+ }
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index aba8b61..2c02d4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -38,7 +38,7 @@
import static android.window.TransitionInfo.FLAG_NO_ANIMATION;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
-import static com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary;
+import static com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived;
import static com.android.window.flags.Flags.ensureWallpaperInTransitions;
import static com.android.window.flags.Flags.migratePredictiveBackTransition;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
@@ -1252,7 +1252,7 @@
@Nullable
public TransitionHandler getHandlerForTakeover(
@NonNull IBinder transition, @NonNull TransitionInfo info) {
- if (!returnAnimationFrameworkLibrary()) {
+ if (!returnAnimationFrameworkLongLived()) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"Trying to get a handler for takeover but the flag is disabled");
return null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 46fe68f..0caa8e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -55,6 +55,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
@@ -240,7 +241,8 @@
boolean applyStartTransactionOnDraw, boolean setTaskCropAndPosition) {
final boolean isFreeform =
taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM;
- final boolean isDragResizeable = isFreeform && taskInfo.isResizeable;
+ final boolean isDragResizeable = DesktopModeFlags.SCALED_RESIZING.isEnabled(mContext)
+ ? isFreeform : isFreeform && taskInfo.isResizeable;
final WindowDecorLinearLayout oldRootView = mResult.mRootView;
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
new file mode 100644
index 0000000..13a805a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.content.Context
+import android.graphics.Point
+import android.graphics.Rect
+import android.view.WindowManager
+import android.window.TaskSnapshot
+import androidx.compose.ui.graphics.toArgb
+import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
+import com.android.wm.shell.shared.split.SplitScreenConstants
+import com.android.wm.shell.splitscreen.SplitScreenController
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
+import com.android.wm.shell.windowdecor.common.DecorThemeUtil
+import com.android.wm.shell.windowdecor.extension.isFullscreen
+import com.android.wm.shell.windowdecor.extension.isMultiWindow
+
+/**
+ * Implementation of [ManageWindowsViewContainer] meant to be used in desktop header and app
+ * handle.
+ */
+class DesktopHandleManageWindowsMenu(
+ private val callerTaskInfo: RunningTaskInfo,
+ private val splitScreenController: SplitScreenController,
+ private val captionX: Int,
+ private val captionWidth: Int,
+ private val windowManagerWrapper: WindowManagerWrapper,
+ context: Context,
+ snapshotList: List<Pair<Int, TaskSnapshot>>,
+ onIconClickListener: ((Int) -> Unit),
+ onOutsideClickListener: (() -> Unit)
+) : ManageWindowsViewContainer(
+ context,
+ DecorThemeUtil(context).getColorScheme(callerTaskInfo).background.toArgb()
+) {
+ private var menuViewContainer: AdditionalViewContainer? = null
+
+ init {
+ show(snapshotList, onIconClickListener, onOutsideClickListener)
+ }
+
+ override fun close() {
+ menuViewContainer?.releaseView()
+ }
+
+ private fun calculateMenuPosition(): Point {
+ val position = Point()
+ val nonFreeformX = (captionX + (captionWidth / 2) - (menuView.menuWidth / 2))
+ when {
+ callerTaskInfo.isFreeform -> {
+ val taskBounds = callerTaskInfo.getConfiguration().windowConfiguration.bounds
+ position.set(taskBounds.left, taskBounds.top)
+ }
+ callerTaskInfo.isFullscreen -> {
+ position.set(nonFreeformX, 0)
+ }
+ callerTaskInfo.isMultiWindow -> {
+ val splitPosition = splitScreenController.getSplitPosition(callerTaskInfo.taskId)
+ val leftOrTopStageBounds = Rect()
+ val rightOrBottomStageBounds = Rect()
+ splitScreenController.getStageBounds(leftOrTopStageBounds, rightOrBottomStageBounds)
+ // TODO(b/343561161): This needs to be calculated differently if the task is in
+ // top/bottom split.
+ when (splitPosition) {
+ SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT -> {
+ position.set(leftOrTopStageBounds.width() + nonFreeformX, /* y= */ 0)
+ }
+
+ SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT -> {
+ position.set(nonFreeformX, /* y= */ 0)
+ }
+ }
+ }
+ }
+ return position
+ }
+
+ override fun addToContainer(menuView: ManageWindowsView) {
+ val menuPosition = calculateMenuPosition()
+ menuViewContainer = AdditionalSystemViewContainer(
+ windowManagerWrapper,
+ callerTaskInfo.taskId,
+ menuPosition.x,
+ menuPosition.y,
+ menuView.menuWidth,
+ menuView.menuHeight,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+ menuView.rootView
+ )
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
new file mode 100644
index 0000000..05391a8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.content.Context
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import android.window.TaskConstants
+import android.window.TaskSnapshot
+import androidx.compose.ui.graphics.toArgb
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
+import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
+import com.android.wm.shell.windowdecor.common.DecorThemeUtil
+import java.util.function.Supplier
+
+/**
+ * Implementation of [ManageWindowsViewContainer] meant to be used in desktop header and app
+ * handle.
+ */
+class DesktopHeaderManageWindowsMenu(
+ private val callerTaskInfo: RunningTaskInfo,
+ private val displayController: DisplayController,
+ private val rootTdaOrganizer: RootTaskDisplayAreaOrganizer,
+ context: Context,
+ private val surfaceControlBuilderSupplier: Supplier<SurfaceControl.Builder>,
+ private val surfaceControlTransactionSupplier: Supplier<SurfaceControl.Transaction>,
+ snapshotList: List<Pair<Int, TaskSnapshot>>,
+ onIconClickListener: ((Int) -> Unit),
+ onOutsideClickListener: (() -> Unit)
+) : ManageWindowsViewContainer(
+ context,
+ DecorThemeUtil(context).getColorScheme(callerTaskInfo).background.toArgb()
+) {
+ private var menuViewContainer: AdditionalViewContainer? = null
+
+ init {
+ show(snapshotList, onIconClickListener, onOutsideClickListener)
+ }
+
+ override fun close() {
+ menuViewContainer?.releaseView()
+ }
+
+ override fun addToContainer(menuView: ManageWindowsView) {
+ val taskBounds = callerTaskInfo.getConfiguration().windowConfiguration.bounds
+ val menuPosition = Point(taskBounds.left, taskBounds.top)
+ val builder = surfaceControlBuilderSupplier.get()
+ rootTdaOrganizer.attachToDisplayArea(callerTaskInfo.displayId, builder)
+ val leash = builder
+ .setName("Manage Windows Menu")
+ .setContainerLayer()
+ .build()
+ val lp = WindowManager.LayoutParams(
+ menuView.menuWidth, menuView.menuHeight,
+ WindowManager.LayoutParams.TYPE_APPLICATION,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSPARENT
+ )
+ val windowManager = WindowlessWindowManager(
+ callerTaskInfo.configuration,
+ leash,
+ null // HostInputToken
+ )
+ val viewHost = SurfaceControlViewHost(
+ context,
+ displayController.getDisplay(callerTaskInfo.displayId), windowManager,
+ "MaximizeMenu"
+ )
+ menuView.let { viewHost.setView(it.rootView, lp) }
+ val t = surfaceControlTransactionSupplier.get()
+ t.setLayer(leash, TaskConstants.TASK_CHILD_LAYER_FLOATING_MENU)
+ .setPosition(leash, menuPosition.x.toFloat(), menuPosition.y.toFloat())
+ .show(leash)
+ t.apply()
+ menuViewContainer = AdditionalViewHostViewContainer(
+ leash, viewHost,
+ surfaceControlTransactionSupplier
+ )
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 7692bd7..b14283f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -39,6 +39,7 @@
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+import static com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer.MANAGE_WINDOWS_MINIMUM_INSTANCES;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -48,6 +49,8 @@
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
+import android.app.IActivityManager;
+import android.app.IActivityTaskManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
@@ -77,6 +80,7 @@
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.widget.Toast;
+import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -125,9 +129,12 @@
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
+import kotlin.Pair;
import kotlin.Unit;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
@@ -406,7 +413,7 @@
final RunningTaskInfo oldTaskInfo = decoration.mTaskInfo;
if (taskInfo.displayId != oldTaskInfo.displayId
- && !Flags.enableAdditionalWindowsAboveStatusBar()) {
+ && !Flags.enableHandleInputFix()) {
removeTaskFromEventReceiver(oldTaskInfo.displayId);
incrementEventReceiverTasks(taskInfo.displayId);
}
@@ -473,7 +480,7 @@
decoration.close();
final int displayId = taskInfo.displayId;
if (mEventReceiversByDisplay.contains(displayId)
- && !Flags.enableAdditionalWindowsAboveStatusBar()) {
+ && !Flags.enableHandleInputFix()) {
removeTaskFromEventReceiver(displayId);
}
// Remove the decoration from the cache last because WindowDecoration#close could still
@@ -586,6 +593,61 @@
mDesktopTasksController.openNewWindow(decoration.mTaskInfo);
}
+ private void onManageWindows(DesktopModeWindowDecoration decoration) {
+ if (decoration == null) {
+ return;
+ }
+ decoration.closeHandleMenu();
+ decoration.createManageWindowsMenu(getTaskSnapshots(decoration.mTaskInfo),
+ /* onIconClickListener= */(Integer requestedTaskId) -> {
+ decoration.closeManageWindowsMenu();
+ mDesktopTasksController.openInstance(decoration.mTaskInfo, requestedTaskId);
+ return Unit.INSTANCE;
+ });
+ }
+
+ private ArrayList<Pair<Integer, TaskSnapshot>> getTaskSnapshots(
+ @NonNull RunningTaskInfo callerTaskInfo
+ ) {
+ final ArrayList<Pair<Integer, TaskSnapshot>> snapshotList = new ArrayList<>();
+ final IActivityManager activityManager = ActivityManager.getService();
+ final IActivityTaskManager activityTaskManagerService = ActivityTaskManager.getService();
+ final List<ActivityManager.RecentTaskInfo> recentTasks;
+ try {
+ recentTasks = mActivityTaskManager.getRecentTasks(
+ Integer.MAX_VALUE,
+ ActivityManager.RECENT_WITH_EXCLUDED,
+ activityManager.getCurrentUser().id);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ final String callerPackageName = callerTaskInfo.baseActivity.getPackageName();
+ for (ActivityManager.RecentTaskInfo info : recentTasks) {
+ if (info.taskId == callerTaskInfo.taskId || info.baseActivity == null) continue;
+ final String infoPackageName = info.baseActivity.getPackageName();
+ if (!infoPackageName.equals(callerPackageName)) {
+ continue;
+ }
+ if (info.baseActivity != null) {
+ if (callerPackageName.equals(infoPackageName)) {
+ // TODO(b/337903443): Fix this returning null for freeform tasks.
+ try {
+ TaskSnapshot screenshot = activityTaskManagerService
+ .getTaskSnapshot(info.taskId, false);
+ if (screenshot == null) {
+ screenshot = activityTaskManagerService
+ .takeTaskSnapshot(info.taskId, false);
+ }
+ snapshotList.add(new Pair(info.taskId, screenshot));
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+ return snapshotList;
+ }
+
private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
View.OnGenericMotionListener, DragDetector.MotionEventHandler {
@@ -642,7 +704,8 @@
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
if (!decoration.isHandleMenuActive()) {
moveTaskToFront(decoration.mTaskInfo);
- decoration.createHandleMenu();
+ decoration.createHandleMenu(checkNumberOfOtherInstances(decoration.mTaskInfo)
+ >= MANAGE_WINDOWS_MINIMUM_INSTANCES);
}
} else if (id == R.id.maximize_window) {
// TODO(b/346441962): move click detection logic into the decor's
@@ -1033,7 +1096,7 @@
relevantDecor.updateHoverAndPressStatus(ev);
final int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- if (!mTransitionDragActive && !Flags.enableAdditionalWindowsAboveStatusBar()) {
+ if (!mTransitionDragActive && !Flags.enableHandleInputFix()) {
relevantDecor.closeHandleMenuIfNeeded(ev);
}
}
@@ -1076,7 +1139,7 @@
}
final boolean shouldStartTransitionDrag =
relevantDecor.checkTouchEventInFocusedCaptionHandle(ev)
- || Flags.enableAdditionalWindowsAboveStatusBar();
+ || Flags.enableHandleInputFix();
if (dragFromStatusBarAllowed && shouldStartTransitionDrag) {
mTransitionDragActive = true;
}
@@ -1350,6 +1413,10 @@
onNewWindow(taskInfo.taskId);
return Unit.INSTANCE;
});
+ windowDecoration.setManageWindowsClickListener(() -> {
+ onManageWindows(windowDecoration);
+ return Unit.INSTANCE;
+ });
windowDecoration.setCaptionListeners(
touchEventListener, touchEventListener, touchEventListener, touchEventListener);
windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
@@ -1357,7 +1424,7 @@
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.relayout(taskInfo, startT, finishT,
false /* applyStartTransactionOnDraw */, false /* shouldSetTaskPositionAndCrop */);
- if (!Flags.enableAdditionalWindowsAboveStatusBar()) {
+ if (!Flags.enableHandleInputFix()) {
incrementEventReceiverTasks(taskInfo.displayId);
}
}
@@ -1441,6 +1508,29 @@
}
}
+ /**
+ * Gets the number of instances of a task running, not including the specified task itself.
+ */
+ private int checkNumberOfOtherInstances(@NonNull RunningTaskInfo info) {
+ // TODO(b/336289597): Rather than returning number of instances, return a list of valid
+ // instances, then refer to the list's size and reuse the list for Manage Windows menu.
+ final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
+ final IActivityManager activityManager = ActivityManager.getService();
+ try {
+ return activityTaskManager.getRecentTasks(Integer.MAX_VALUE,
+ ActivityManager.RECENT_WITH_EXCLUDED,
+ activityManager.getCurrentUserId()).getList().stream().filter(
+ recentTaskInfo -> (recentTaskInfo.taskId != info.taskId
+ && recentTaskInfo.baseActivity != null
+ && recentTaskInfo.baseActivity.getPackageName()
+ .equals(info.baseActivity.getPackageName())
+ )
+ ).toList().size();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
static class InputMonitorFactory {
InputMonitor create(InputManager inputManager, int displayId) {
return inputManager.monitorGestureInput("caption-touch", displayId);
@@ -1490,7 +1580,7 @@
&& Flags.enableDesktopWindowingImmersiveHandleHiding()) {
decor.onInsetsStateChanged(insetsState);
}
- if (!Flags.enableAdditionalWindowsAboveStatusBar()) {
+ if (!Flags.enableHandleInputFix()) {
// If status bar inset is visible, top task is not in immersive mode.
// This value is only needed when the App Handle input is being handled
// through the global input monitor (hence the flag check) to ignore gestures
@@ -1513,14 +1603,27 @@
Transitions transitions,
InteractionJankMonitor interactionJankMonitor,
Supplier<SurfaceControl.Transaction> transactionFactory) {
- if (!DesktopModeStatus.isVeiledResizeEnabled()) {
- return new FluidResizeTaskPositioner(
- taskOrganizer, transitions, windowDecoration, displayController,
- dragStartListener, transactionFactory);
+ final TaskPositioner taskPositioner = DesktopModeStatus.isVeiledResizeEnabled()
+ ? new VeiledResizeTaskPositioner(
+ taskOrganizer,
+ windowDecoration,
+ displayController,
+ dragStartListener,
+ transitions,
+ interactionJankMonitor)
+ : new FluidResizeTaskPositioner(
+ taskOrganizer,
+ transitions,
+ windowDecoration,
+ displayController,
+ dragStartListener,
+ transactionFactory);
+
+ if (DesktopModeFlags.SCALED_RESIZING.isEnabled(windowDecoration.mContext)) {
+ return new FixedAspectRatioTaskPositionerDecorator(windowDecoration,
+ taskPositioner);
}
- return new VeiledResizeTaskPositioner(
- taskOrganizer, windowDecoration, displayController,
- dragStartListener, transitions, interactionJankMonitor);
+ return taskPositioner;
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 1409d30..d43ee44 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -64,6 +64,7 @@
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.ImageButton;
+import android.window.TaskSnapshot;
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
@@ -86,6 +87,7 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
+import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder;
@@ -93,9 +95,12 @@
import com.android.wm.shell.windowdecor.viewholder.WindowDecorationViewHolder;
import com.android.wm.shell.windowdecor.viewhost.WindowDecorViewHostSupplier;
+import kotlin.Pair;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
+import kotlin.jvm.functions.Function1;
+import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -131,6 +136,7 @@
private Function0<Unit> mOnToFullscreenClickListener;
private Function0<Unit> mOnToSplitscreenClickListener;
private Function0<Unit> mOnNewWindowClickListener;
+ private Function0<Unit> mOnManageWindowsClickListener;
private DragPositioningCallback mDragPositioningCallback;
private DragResizeInputListener mDragResizeListener;
private DragDetector mDragDetector;
@@ -140,6 +146,8 @@
private final Point mPositionInParent = new Point();
private HandleMenu mHandleMenu;
+ private boolean mMinimumInstancesFound;
+ private ManageWindowsViewContainer mManageWindowsMenu;
private MaximizeMenu mMaximizeMenu;
@@ -285,6 +293,14 @@
mOnNewWindowClickListener = listener;
}
+ /**
+ * Registers a listener to be called when the decoration's manage windows action is
+ * triggered.
+ */
+ void setManageWindowsClickListener(Function0<Unit> listener) {
+ mOnManageWindowsClickListener = listener;
+ }
+
void setCaptionListeners(
View.OnClickListener onCaptionButtonClickListener,
View.OnTouchListener onCaptionTouchListener,
@@ -439,7 +455,7 @@
}
private void updateDragResizeListener(SurfaceControl oldDecorationSurface) {
- if (!isDragResizable(mTaskInfo)) {
+ if (!isDragResizable(mTaskInfo, mContext)) {
if (!mTaskInfo.positionInParent.equals(mPositionInParent)) {
// We still want to track caption bar's exclusion region on a non-resizeable task.
updateExclusionRegion();
@@ -481,12 +497,16 @@
}
}
- private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo) {
+ private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo,
+ Context context) {
+ if (DesktopModeFlags.SCALED_RESIZING.isEnabled(context)) {
+ return taskInfo.isFreeform();
+ }
return taskInfo.isFreeform() && taskInfo.isResizeable;
}
private void updateMaximizeMenu(SurfaceControl.Transaction startT) {
- if (!isDragResizable(mTaskInfo) || !isMaximizeMenuActive()) {
+ if (!isDragResizable(mTaskInfo, mContext) || !isMaximizeMenuActive()) {
return;
}
if (!mTaskInfo.isVisible()) {
@@ -516,7 +536,7 @@
*/
void disposeStatusBarInputLayer() {
if (!isAppHandle(mWindowDecorViewHolder)
- || !Flags.enableAdditionalWindowsAboveStatusBar()) {
+ || !Flags.enableHandleInputFix()) {
return;
}
((AppHandleViewHolder) mWindowDecorViewHolder).disposeStatusBarInputLayer();
@@ -528,7 +548,8 @@
mResult.mRootView,
mOnCaptionTouchListener,
mOnCaptionButtonClickListener,
- mWindowManagerWrapper
+ mWindowManagerWrapper,
+ mHandler
);
} else if (mRelayoutParams.mLayoutResId
== R.layout.desktop_mode_app_header) {
@@ -612,7 +633,7 @@
}
controlsElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.END;
relayoutParams.mOccludingCaptionElements.add(controlsElement);
- } else if (isAppHandle && !Flags.enableAdditionalWindowsAboveStatusBar()) {
+ } else if (isAppHandle && !Flags.enableHandleInputFix()) {
// The focused decor (fullscreen/split) does not need to handle input because input in
// the App Handle is handled by the InputMonitor in DesktopModeWindowDecorViewModel.
// Note: This does not apply with the above flag enabled as the status bar input layer
@@ -941,9 +962,10 @@
/**
* Updates app info and creates and displays handle menu window.
*/
- void createHandleMenu() {
+ void createHandleMenu(boolean minimumInstancesFound) {
// Requests assist content. When content is received, calls {@link #onAssistContentReceived}
// which sets app info and creates the handle menu.
+ mMinimumInstancesFound = minimumInstancesFound;
mAssistContentRequester.requestAssistContent(
mTaskInfo.taskId, this::onAssistContentReceived);
}
@@ -956,8 +978,10 @@
mWebUri = assistContent == null ? null : assistContent.getWebUri();
loadAppInfoIfNeeded();
updateGenericLink();
-
- // Create and display handle menu
+ final boolean supportsMultiInstance = mMultiInstanceHelper
+ .supportsMultiInstanceSplit(mTaskInfo.baseActivity);
+ final boolean shouldShowManageWindowsButton = supportsMultiInstance
+ && mMinimumInstancesFound;
mHandleMenu = mHandleMenuFactory.create(
this,
mWindowManagerWrapper,
@@ -966,9 +990,8 @@
mAppName,
mSplitScreenController,
DesktopModeStatus.canEnterDesktopMode(mContext),
- Flags.enableDesktopWindowingMultiInstanceFeatures()
- && mMultiInstanceHelper
- .supportsMultiInstanceSplit(mTaskInfo.baseActivity),
+ supportsMultiInstance,
+ shouldShowManageWindowsButton,
getBrowserLink(),
mResult.mCaptionWidth,
mResult.mCaptionHeight,
@@ -984,6 +1007,7 @@
/* onToFullscreenClickListener= */ mOnToFullscreenClickListener,
/* onToSplitScreenClickListener= */ mOnToSplitscreenClickListener,
/* onNewWindowClickListener= */ mOnNewWindowClickListener,
+ /* onManageWindowsClickListener= */ mOnManageWindowsClickListener,
/* openInBrowserClickListener= */ (uri) -> {
mOpenInBrowserClickListener.accept(uri);
onCapturedLinkExpired();
@@ -998,6 +1022,47 @@
return Unit.INSTANCE;
}
);
+ mMinimumInstancesFound = false;
+ }
+
+ void createManageWindowsMenu(@NonNull List<Pair<Integer, TaskSnapshot>> snapshotList,
+ @NonNull Function1<Integer, Unit> onIconClickListener
+ ) {
+ if (mTaskInfo.isFreeform()) {
+ mManageWindowsMenu = new DesktopHeaderManageWindowsMenu(
+ mTaskInfo,
+ mDisplayController,
+ mRootTaskDisplayAreaOrganizer,
+ mContext,
+ mSurfaceControlBuilderSupplier,
+ mSurfaceControlTransactionSupplier,
+ snapshotList,
+ onIconClickListener,
+ /* onOutsideClickListener= */ () -> {
+ closeManageWindowsMenu();
+ return Unit.INSTANCE;
+ }
+ );
+ } else {
+ mManageWindowsMenu = new DesktopHandleManageWindowsMenu(
+ mTaskInfo,
+ mSplitScreenController,
+ getCaptionX(),
+ mResult.mCaptionWidth,
+ mWindowManagerWrapper,
+ mContext,
+ snapshotList,
+ onIconClickListener,
+ /* onOutsideClickListener= */ () -> {
+ closeManageWindowsMenu();
+ return Unit.INSTANCE;
+ }
+ );
+ }
+ }
+
+ void closeManageWindowsMenu() {
+ mManageWindowsMenu.close();
}
private void updateGenericLink() {
@@ -1093,13 +1158,13 @@
*/
boolean checkTouchEventInFocusedCaptionHandle(MotionEvent ev) {
if (isHandleMenuActive() || !isAppHandle(mWindowDecorViewHolder)
- || Flags.enableAdditionalWindowsAboveStatusBar()) {
+ || Flags.enableHandleInputFix()) {
return false;
}
// The status bar input layer can only receive input in handle coordinates to begin with,
// so checking coordinates is unnecessary as input is always within handle bounds.
if (isAppHandle(mWindowDecorViewHolder)
- && Flags.enableAdditionalWindowsAboveStatusBar()
+ && Flags.enableHandleInputFix()
&& isCaptionVisible()) {
return true;
}
@@ -1136,7 +1201,7 @@
* @param ev the MotionEvent to compare
*/
void checkTouchEvent(MotionEvent ev) {
- if (mResult.mRootView == null || Flags.enableAdditionalWindowsAboveStatusBar()) return;
+ if (mResult.mRootView == null || Flags.enableHandleInputFix()) return;
final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption);
final View handle = caption.findViewById(R.id.caption_handle);
final boolean inHandle = !isHandleMenuActive()
@@ -1149,7 +1214,7 @@
// If the whole handle menu can be touched directly, rely on FLAG_WATCH_OUTSIDE_TOUCH.
// This is for the case that some of the handle menu is underneath the status bar.
if (isAppHandle(mWindowDecorViewHolder)
- && !Flags.enableAdditionalWindowsAboveStatusBar()) {
+ && !Flags.enableHandleInputFix()) {
mHandleMenu.checkMotionEvent(ev);
closeHandleMenuIfNeeded(ev);
}
@@ -1163,7 +1228,7 @@
* @param ev the MotionEvent to compare against.
*/
void updateHoverAndPressStatus(MotionEvent ev) {
- if (mResult.mRootView == null || Flags.enableAdditionalWindowsAboveStatusBar()) return;
+ if (mResult.mRootView == null || Flags.enableHandleInputFix()) return;
final View handle = mResult.mRootView.findViewById(R.id.caption_handle);
final boolean inHandle = !isHandleMenuActive()
&& checkTouchEventInFocusedCaptionHandle(ev);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index cb9781e..cad3462 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -84,22 +84,47 @@
repositionTaskBounds.set(taskBoundsAtDragStart);
+ boolean isAspectRatioMaintained = true;
// Make sure the new resizing destination in any direction falls within the stable bounds.
if ((ctrlType & CTRL_TYPE_LEFT) != 0) {
repositionTaskBounds.left = Math.max(repositionTaskBounds.left + (int) delta.x,
stableBounds.left);
+ if (repositionTaskBounds.left == stableBounds.left
+ && repositionTaskBounds.left + (int) delta.x != stableBounds.left) {
+ // If the task edge have been set to the stable bounds and not due to the users
+ // drag, the aspect ratio of the task will not be maintained.
+ isAspectRatioMaintained = false;
+ }
}
if ((ctrlType & CTRL_TYPE_RIGHT) != 0) {
repositionTaskBounds.right = Math.min(repositionTaskBounds.right + (int) delta.x,
stableBounds.right);
+ if (repositionTaskBounds.right == stableBounds.right
+ && repositionTaskBounds.right + (int) delta.x != stableBounds.right) {
+ // If the task edge have been set to the stable bounds and not due to the users
+ // drag, the aspect ratio of the task will not be maintained.
+ isAspectRatioMaintained = false;
+ }
}
if ((ctrlType & CTRL_TYPE_TOP) != 0) {
repositionTaskBounds.top = Math.max(repositionTaskBounds.top + (int) delta.y,
stableBounds.top);
+ if (repositionTaskBounds.top == stableBounds.top
+ && repositionTaskBounds.top + (int) delta.y != stableBounds.top) {
+ // If the task edge have been set to the stable bounds and not due to the users
+ // drag, the aspect ratio of the task will not be maintained.
+ isAspectRatioMaintained = false;
+ }
}
if ((ctrlType & CTRL_TYPE_BOTTOM) != 0) {
repositionTaskBounds.bottom = Math.min(repositionTaskBounds.bottom + (int) delta.y,
stableBounds.bottom);
+ if (repositionTaskBounds.bottom == stableBounds.bottom
+ && repositionTaskBounds.bottom + (int) delta.y != stableBounds.bottom) {
+ // If the task edge have been set to the stable bounds and not due to the users
+ // drag, the aspect ratio of the task will not be maintained.
+ isAspectRatioMaintained = false;
+ }
}
// If width or height are negative or exceeding the width or height constraints, revert the
@@ -108,11 +133,24 @@
windowDecoration)) {
repositionTaskBounds.right = oldRight;
repositionTaskBounds.left = oldLeft;
+ isAspectRatioMaintained = false;
}
if (isExceedingHeightConstraint(repositionTaskBounds, stableBounds, displayController,
windowDecoration)) {
repositionTaskBounds.top = oldTop;
repositionTaskBounds.bottom = oldBottom;
+ isAspectRatioMaintained = false;
+ }
+
+ // If the application is unresizeable and any bounds have been set back to their old
+ // location or to a stable bound edge, reset all the bounds to maintain the applications
+ // aspect ratio.
+ if (DesktopModeFlags.SCALED_RESIZING.isEnabled(windowDecoration.mDecorWindowContext)
+ && !isAspectRatioMaintained && !windowDecoration.mTaskInfo.isResizeable) {
+ repositionTaskBounds.top = oldTop;
+ repositionTaskBounds.bottom = oldBottom;
+ repositionTaskBounds.right = oldRight;
+ repositionTaskBounds.left = oldLeft;
}
// If there are no changes to the bounds after checking new bounds against minimum and
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
index e8131a0..3885761 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecorator.kt
@@ -16,8 +16,10 @@
package com.android.wm.shell.windowdecor
+import android.app.ActivityManager.RunningTaskInfo
import android.graphics.PointF
import android.graphics.Rect
+import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
@@ -51,8 +53,7 @@
return super.onDragPositioningStart(originalCtrlType, x, y)
}
- lastRepositionedBounds.set(
- windowDecoration.mTaskInfo.configuration.windowConfiguration.bounds)
+ lastRepositionedBounds.set(getBounds(windowDecoration.mTaskInfo))
startingPoint.set(x, y)
lastValidPoint.set(x, y)
val startingBoundWidth = lastRepositionedBounds.width()
@@ -255,4 +256,9 @@
private fun requiresFixedAspectRatio(): Boolean {
return originalCtrlType.isResizing() && !windowDecoration.mTaskInfo.isResizeable
}
+
+ @VisibleForTesting
+ fun getBounds(taskInfo: RunningTaskInfo): Rect {
+ return taskInfo.configuration.windowConfiguration.bounds
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index 748046e..faffe4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -71,6 +71,7 @@
private val splitScreenController: SplitScreenController,
private val shouldShowWindowingPill: Boolean,
private val shouldShowNewWindowButton: Boolean,
+ private val shouldShowManageWindowsButton: Boolean,
private val openInBrowserLink: Uri?,
private val captionWidth: Int,
private val captionHeight: Int,
@@ -80,7 +81,7 @@
private val taskInfo: RunningTaskInfo = parentDecor.mTaskInfo
private val isViewAboveStatusBar: Boolean
- get() = (Flags.enableAdditionalWindowsAboveStatusBar() && !taskInfo.isFreeform)
+ get() = (Flags.enableHandleInputFix() && !taskInfo.isFreeform)
private val pillElevation: Int = loadDimensionPixelSize(
R.dimen.desktop_mode_handle_menu_pill_elevation)
@@ -119,6 +120,7 @@
onToFullscreenClickListener: () -> Unit,
onToSplitScreenClickListener: () -> Unit,
onNewWindowClickListener: () -> Unit,
+ onManageWindowsClickListener: () -> Unit,
openInBrowserClickListener: (Uri) -> Unit,
onCloseMenuClickListener: () -> Unit,
onOutsideTouchListener: () -> Unit,
@@ -133,6 +135,7 @@
onToFullscreenClickListener = onToFullscreenClickListener,
onToSplitScreenClickListener = onToSplitScreenClickListener,
onNewWindowClickListener = onNewWindowClickListener,
+ onManageWindowsClickListener = onManageWindowsClickListener,
openInBrowserClickListener = openInBrowserClickListener,
onCloseMenuClickListener = onCloseMenuClickListener,
onOutsideTouchListener = onOutsideTouchListener,
@@ -150,6 +153,7 @@
onToFullscreenClickListener: () -> Unit,
onToSplitScreenClickListener: () -> Unit,
onNewWindowClickListener: () -> Unit,
+ onManageWindowsClickListener: () -> Unit,
openInBrowserClickListener: (Uri) -> Unit,
onCloseMenuClickListener: () -> Unit,
onOutsideTouchListener: () -> Unit
@@ -160,13 +164,15 @@
captionHeight = captionHeight,
shouldShowWindowingPill = shouldShowWindowingPill,
shouldShowBrowserPill = shouldShowBrowserPill,
- shouldShowNewWindowButton = shouldShowNewWindowButton
+ shouldShowNewWindowButton = shouldShowNewWindowButton,
+ shouldShowManageWindowsButton = shouldShowManageWindowsButton
).apply {
bind(taskInfo, appIconBitmap, appName)
this.onToDesktopClickListener = onToDesktopClickListener
this.onToFullscreenClickListener = onToFullscreenClickListener
this.onToSplitScreenClickListener = onToSplitScreenClickListener
this.onNewWindowClickListener = onNewWindowClickListener
+ this.onManageWindowsClickListener = onManageWindowsClickListener
this.onOpenInBrowserClickListener = {
openInBrowserClickListener.invoke(openInBrowserLink!!)
}
@@ -177,7 +183,7 @@
val x = handleMenuPosition.x.toInt()
val y = handleMenuPosition.y.toInt()
handleMenuViewContainer =
- if (!taskInfo.isFreeform && Flags.enableAdditionalWindowsAboveStatusBar()) {
+ if (!taskInfo.isFreeform && Flags.enableHandleInputFix()) {
AdditionalSystemViewContainer(
windowManagerWrapper = windowManagerWrapper,
taskId = taskInfo.taskId,
@@ -212,7 +218,7 @@
menuX = marginMenuStart
menuY = marginMenuTop
} else {
- if (Flags.enableAdditionalWindowsAboveStatusBar()) {
+ if (Flags.enableHandleInputFix()) {
// In a focused decor, we use global coordinates for handle menu. Therefore we
// need to account for other factors like split stage and menu/handle width to
// center the menu.
@@ -372,7 +378,13 @@
R.dimen.desktop_mode_handle_menu_new_window_height
)
}
- if (!SHOULD_SHOW_SCREENSHOT_BUTTON && !shouldShowNewWindowButton) {
+ if (!shouldShowManageWindowsButton) {
+ menuHeight -= loadDimensionPixelSize(
+ R.dimen.desktop_mode_handle_menu_manage_windows_height
+ )
+ }
+ if (!SHOULD_SHOW_SCREENSHOT_BUTTON && !shouldShowNewWindowButton
+ && !shouldShowManageWindowsButton) {
menuHeight -= pillTopMargin
}
if (!shouldShowBrowserPill) {
@@ -405,7 +417,8 @@
captionHeight: Int,
private val shouldShowWindowingPill: Boolean,
private val shouldShowBrowserPill: Boolean,
- private val shouldShowNewWindowButton: Boolean
+ private val shouldShowNewWindowButton: Boolean,
+ private val shouldShowManageWindowsButton: Boolean
) {
val rootView = LayoutInflater.from(context)
.inflate(R.layout.desktop_mode_window_decor_handle_menu, null /* root */) as View
@@ -430,6 +443,8 @@
private val moreActionsPill = rootView.requireViewById<View>(R.id.more_actions_pill)
private val screenshotBtn = moreActionsPill.requireViewById<Button>(R.id.screenshot_button)
private val newWindowBtn = moreActionsPill.requireViewById<Button>(R.id.new_window_button)
+ private val manageWindowBtn = moreActionsPill
+ .requireViewById<Button>(R.id.manage_windows_button)
// Open in Browser Pill.
private val openInBrowserPill = rootView.requireViewById<View>(R.id.open_in_browser_pill)
@@ -446,6 +461,7 @@
var onToFullscreenClickListener: (() -> Unit)? = null
var onToSplitScreenClickListener: (() -> Unit)? = null
var onNewWindowClickListener: (() -> Unit)? = null
+ var onManageWindowsClickListener: (() -> Unit)? = null
var onOpenInBrowserClickListener: (() -> Unit)? = null
var onCloseMenuClickListener: (() -> Unit)? = null
var onOutsideTouchListener: (() -> Unit)? = null
@@ -457,6 +473,7 @@
browserBtn.setOnClickListener { onOpenInBrowserClickListener?.invoke() }
collapseMenuButton.setOnClickListener { onCloseMenuClickListener?.invoke() }
newWindowBtn.setOnClickListener { onNewWindowClickListener?.invoke() }
+ manageWindowBtn.setOnClickListener { onManageWindowsClickListener?.invoke() }
rootView.setOnTouchListener { _, event ->
if (event.actionMasked == ACTION_OUTSIDE) {
@@ -587,6 +604,7 @@
private fun bindMoreActionsPill(style: MenuStyle) {
moreActionsPill.apply {
isGone = !shouldShowNewWindowButton && !SHOULD_SHOW_SCREENSHOT_BUTTON
+ && !shouldShowManageWindowsButton
}
screenshotBtn.apply {
isGone = !SHOULD_SHOW_SCREENSHOT_BUTTON
@@ -603,6 +621,13 @@
setTextColor(style.textColor)
compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
}
+ manageWindowBtn.apply {
+ isGone = !shouldShowManageWindowsButton
+ background.colorFilter =
+ BlendModeColorFilter(style.backgroundColor, BlendMode.MULTIPLY)
+ setTextColor(style.textColor)
+ compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
+ }
}
private fun bindOpenInBrowserPill(style: MenuStyle) {
@@ -643,6 +668,7 @@
splitScreenController: SplitScreenController,
shouldShowWindowingPill: Boolean,
shouldShowNewWindowButton: Boolean,
+ shouldShowManageWindowsButton: Boolean,
openInBrowserLink: Uri?,
captionWidth: Int,
captionHeight: Int,
@@ -661,6 +687,7 @@
splitScreenController: SplitScreenController,
shouldShowWindowingPill: Boolean,
shouldShowNewWindowButton: Boolean,
+ shouldShowManageWindowsButton: Boolean,
openInBrowserLink: Uri?,
captionWidth: Int,
captionHeight: Int,
@@ -675,6 +702,7 @@
splitScreenController,
shouldShowWindowingPill,
shouldShowNewWindowButton,
+ shouldShowManageWindowsButton,
openInBrowserLink,
captionWidth,
captionHeight,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt
index 18757ef..cf82bb4f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt
@@ -39,7 +39,7 @@
lateinit var taskInfo: RunningTaskInfo
override fun onHoverEvent(motionEvent: MotionEvent): Boolean {
- if (Flags.enableAdditionalWindowsAboveStatusBar() || taskInfo.isFreeform) {
+ if (Flags.enableHandleInputFix() || taskInfo.isFreeform) {
return super.onHoverEvent(motionEvent)
} else {
return false
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
index 9ef4b8c..9c7d644 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
@@ -22,6 +22,7 @@
import android.graphics.Color
import android.graphics.Point
import android.hardware.input.InputManager
+import android.os.Handler
import android.view.MotionEvent.ACTION_DOWN
import android.view.SurfaceControl
import android.view.View
@@ -44,7 +45,8 @@
rootView: View,
onCaptionTouchListener: View.OnTouchListener,
onCaptionButtonClickListener: OnClickListener,
- private val windowManagerWrapper: WindowManagerWrapper
+ private val windowManagerWrapper: WindowManagerWrapper,
+ private val handler: Handler
) : WindowDecorationViewHolder(rootView) {
companion object {
@@ -54,6 +56,7 @@
private val captionView: View = rootView.requireViewById(R.id.desktop_mode_caption)
private val captionHandle: ImageButton = rootView.requireViewById(R.id.caption_handle)
private val inputManager = context.getSystemService(InputManager::class.java)
+ private var statusBarInputLayerExists = false
// An invisible View that takes up the same coordinates as captionHandle but is layered
// above the status bar. The purpose of this View is to receive input intended for
@@ -78,14 +81,18 @@
// If handle is not in status bar region(i.e., bottom stage in vertical split),
// do not create an input layer
if (position.y >= SystemBarUtils.getStatusBarHeight(context)) return
- if (!isCaptionVisible && hasStatusBarInputLayer() ) {
+ if (!isCaptionVisible && statusBarInputLayerExists) {
disposeStatusBarInputLayer()
return
}
- if (hasStatusBarInputLayer()) {
- updateStatusBarInputLayer(position)
+ // Input layer view creation / modification takes a significant amount of time;
+ // post them so we don't hold up DesktopModeWindowDecoration#relayout.
+ if (statusBarInputLayerExists) {
+ handler.post { updateStatusBarInputLayer(position) }
} else {
- createStatusBarInputLayer(position, width, height)
+ // Input layer is created on a delay; prevent multiple from being created.
+ statusBarInputLayerExists = true
+ handler.post { createStatusBarInputLayer(position, width, height) }
}
}
@@ -100,12 +107,13 @@
private fun createStatusBarInputLayer(handlePosition: Point,
handleWidth: Int,
handleHeight: Int) {
- if (!Flags.enableAdditionalWindowsAboveStatusBar()) return
+ if (!Flags.enableHandleInputFix()) return
statusBarInputLayer = AdditionalSystemViewContainer(context, windowManagerWrapper,
taskInfo.taskId, handlePosition.x, handlePosition.y, handleWidth, handleHeight,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ )
val view = statusBarInputLayer?.view ?: error("Unable to find statusBarInputLayer View")
- val lp = statusBarInputLayer?.lp ?: error("Unable to find statusBarInputLayer" +
+ val lp = statusBarInputLayer?.lp ?: error("Unable to find statusBarInputLayer " +
"LayoutParams")
lp.title = "Handle Input Layer of task " + taskInfo.taskId
lp.setTrustedOverlay()
@@ -130,12 +138,11 @@
}
private fun updateStatusBarInputLayer(globalPosition: Point) {
- statusBarInputLayer?.setPosition(SurfaceControl.Transaction(), globalPosition.x.toFloat(),
- globalPosition.y.toFloat()) ?: return
- }
-
- private fun hasStatusBarInputLayer(): Boolean {
- return statusBarInputLayer != null
+ statusBarInputLayer?.setPosition(
+ SurfaceControl.Transaction(),
+ globalPosition.x.toFloat(),
+ globalPosition.y.toFloat()
+ ) ?: return
}
/**
@@ -143,8 +150,11 @@
* is not visible.
*/
fun disposeStatusBarInputLayer() {
- statusBarInputLayer?.releaseView()
- statusBarInputLayer = null
+ statusBarInputLayerExists = false
+ handler.post {
+ statusBarInputLayer?.releaseView()
+ statusBarInputLayer = null
+ }
}
private fun getCaptionHandleBarColor(taskInfo: RunningTaskInfo): Int {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
index 139e679..5156e47 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHost.kt
@@ -19,51 +19,33 @@
import android.content.res.Configuration
import android.view.Display
import android.view.SurfaceControl
-import android.view.SurfaceControlViewHost
import android.view.View
import android.view.WindowManager
-import android.view.WindowlessWindowManager
import androidx.tracing.Trace
import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.shared.annotations.ShellMainThread
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
-typealias SurfaceControlViewHostFactory =
- (Context, Display, WindowlessWindowManager, String) -> SurfaceControlViewHost
/**
- * A default implementation of [WindowDecorViewHost] backed by a [SurfaceControlViewHost].
+ * A default implementation of [WindowDecorViewHost] backed by a [SurfaceControlViewHostAdapter].
*
- * It does not support swapping the root view added to the VRI of the [SurfaceControlViewHost], and
- * any attempts to do will throw, which means that once a [View] is added using [updateView] or
- * [updateViewAsync], only its properties and binding may be changed, its children views may be
- * added, removed or changed and its [WindowManager.LayoutParams] may be changed.
- * It also supports asynchronously updating the view hierarchy using [updateViewAsync], in which
+ * It supports asynchronously updating the view hierarchy using [updateViewAsync], in which
* case the update work will be posted on the [ShellMainThread] with no delay.
*/
class DefaultWindowDecorViewHost(
- private val context: Context,
+ context: Context,
@ShellMainThread private val mainScope: CoroutineScope,
- private val display: Display,
- private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = { c, d, wwm, s ->
- SurfaceControlViewHost(c, d, wwm, s)
- }
+ display: Display,
+ @VisibleForTesting val viewHostAdapter: SurfaceControlViewHostAdapter =
+ SurfaceControlViewHostAdapter(context, display)
) : WindowDecorViewHost {
- private val rootSurface: SurfaceControl = SurfaceControl.Builder()
- .setName("DefaultWindowDecorViewHost surface")
- .setContainerLayer()
- .setCallsite("DefaultWindowDecorViewHost#init")
- .build()
-
- private var wwm: WindowlessWindowManager? = null
- @VisibleForTesting
- var viewHost: SurfaceControlViewHost? = null
private var currentUpdateJob: Job? = null
override val surfaceControl: SurfaceControl
- get() = rootSurface
+ get() = viewHostAdapter.rootSurface
override fun updateView(
view: View,
@@ -92,8 +74,7 @@
override fun release(t: SurfaceControl.Transaction) {
clearCurrentUpdateJob()
- viewHost?.release()
- t.remove(rootSurface)
+ viewHostAdapter.release(t)
}
private fun updateViewHost(
@@ -102,45 +83,15 @@
configuration: Configuration,
onDrawTransaction: SurfaceControl.Transaction?
) {
- Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost")
- if (wwm == null) {
- wwm = WindowlessWindowManager(configuration, rootSurface, null)
- }
- requireWindowlessWindowManager().setConfiguration(configuration)
- if (viewHost == null) {
- viewHost = surfaceControlViewHostFactory.invoke(
- context,
- display,
- requireWindowlessWindowManager(),
- "DefaultWindowDecorViewHost#updateViewHost"
- )
- }
+ viewHostAdapter.prepareViewHost(configuration)
onDrawTransaction?.let {
- requireViewHost().rootSurfaceControl.applyTransactionOnDraw(it)
+ viewHostAdapter.applyTransactionOnDraw(it)
}
- if (requireViewHost().view == null) {
- Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-setView")
- requireViewHost().setView(view, attrs)
- Trace.endSection()
- } else {
- check(requireViewHost().view == view) { "Changing view is not allowed" }
- Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-relayout")
- requireViewHost().relayout(attrs)
- Trace.endSection()
- }
- Trace.endSection()
+ viewHostAdapter.updateView(view, attrs)
}
private fun clearCurrentUpdateJob() {
currentUpdateJob?.cancel()
currentUpdateJob = null
}
-
- private fun requireWindowlessWindowManager(): WindowlessWindowManager {
- return wwm ?: error("Expected non-null windowless window manager")
- }
-
- private fun requireViewHost(): SurfaceControlViewHost {
- return viewHost ?: error("Expected non-null view host")
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplier.kt
new file mode 100644
index 0000000..b04188f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplier.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.content.Context
+import android.os.Trace
+import android.util.Pools
+import android.view.Display
+import android.view.SurfaceControl
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import com.android.wm.shell.sysui.ShellInit
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * A [WindowDecorViewHostSupplier] backed by a pool to allow recycling view hosts which may be
+ * expensive to recreate for each new/updated window decoration.
+ *
+ * Callers can obtain [ReusableWindowDecorViewHost] using [acquire], which will return a pooled
+ * object if available, or create a new instance and return it if needed. When done using a
+ * [ReusableWindowDecorViewHost], it must be released using [release] to allow it to be sent back
+ * into the pool and reused later on.
+ *
+ * This class also supports pre-warming [ReusableWindowDecorViewHost] instances, which will be put
+ * into the pool immediately after creation.
+ */
+class PooledWindowDecorViewHostSupplier(
+ private val context: Context,
+ @ShellMainThread private val mainScope: CoroutineScope,
+ shellInit: ShellInit,
+ private val viewHostFactory: ReusableWindowDecorViewHost.Factory =
+ ReusableWindowDecorViewHost.DefaultFactory,
+ maxPoolSize: Int,
+ private val preWarmSize: Int,
+) : WindowDecorViewHostSupplier<ReusableWindowDecorViewHost> {
+
+ private val pool: Pools.Pool<ReusableWindowDecorViewHost> = Pools.SynchronizedPool(maxPoolSize)
+ private var nextDecorViewHostId = 0
+
+ init {
+ require(preWarmSize <= maxPoolSize) { "Pre-warm size should not exceed pool size" }
+ shellInit.addInitCallback(this::onShellInit, this)
+ }
+
+ private fun onShellInit() {
+ if (preWarmSize <= 0) {
+ return
+ }
+ preWarmViewHosts(preWarmSize)
+ }
+
+ private fun preWarmViewHosts(preWarmSize: Int) {
+ mainScope.launch {
+ // Applying isn't needed, as the surface was never actually shown.
+ val t = SurfaceControl.Transaction()
+ repeat(preWarmSize) {
+ val warmedViewHost = create(context, context.display).apply {
+ warmUp()
+ }
+ // Put the warmed view host in the pool by releasing it.
+ release(warmedViewHost, t)
+ }
+ }
+ }
+
+ override fun acquire(context: Context, display: Display): ReusableWindowDecorViewHost {
+ val reusedDecorViewHost = pool.acquire()
+ if (reusedDecorViewHost != null) {
+ return reusedDecorViewHost
+ }
+ Trace.beginSection("WindowDecorViewHostPool#acquire-new")
+ val newDecorViewHost = create(context, display)
+ Trace.endSection()
+ return newDecorViewHost
+ }
+
+ override fun release(viewHost: ReusableWindowDecorViewHost, t: SurfaceControl.Transaction) {
+ val cached = pool.release(viewHost)
+ if (!cached) {
+ viewHost.release(t)
+ }
+ }
+
+ private fun create(context: Context, display: Display): ReusableWindowDecorViewHost {
+ return viewHostFactory.create(
+ context,
+ mainScope,
+ display,
+ nextDecorViewHostId++
+ )
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHost.kt
new file mode 100644
index 0000000..64536d1
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHost.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.PixelFormat
+import android.os.Trace
+import android.view.Display
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+import android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+import android.view.WindowManager.LayoutParams.TYPE_APPLICATION
+import android.widget.FrameLayout
+import com.android.internal.annotations.VisibleForTesting
+import com.android.wm.shell.shared.annotations.ShellMainThread
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+
+/**
+ * An implementation of [WindowDecorViewHost] that supports:
+ * 1) Replacing the root [View], meaning [WindowDecorViewHost.updateView] maybe be
+ * called with different [View] instances. This is useful when reusing [WindowDecorViewHost]s
+ * instances for vastly different view hierarchies, such as Desktop Windowing's App Handles and
+ * App Headers.
+ * 2) Pre-warming of the underlying [SurfaceControlViewHost]s. Useful because their creation and
+ * first root view assignment are expensive, which is undesirable in latency-sensitive code
+ * paths like during a shell transition.
+ */
+class ReusableWindowDecorViewHost(
+ private val context: Context,
+ @ShellMainThread private val mainScope: CoroutineScope,
+ display: Display,
+ val id: Int,
+ @VisibleForTesting val viewHostAdapter: SurfaceControlViewHostAdapter =
+ SurfaceControlViewHostAdapter(context, display)
+) : WindowDecorViewHost, Warmable {
+
+ @VisibleForTesting
+ val rootView = FrameLayout(context)
+
+ private var currentUpdateJob: Job? = null
+
+ override val surfaceControl: SurfaceControl
+ get() = viewHostAdapter.rootSurface
+
+ override fun warmUp() {
+ if (viewHostAdapter.isInitialized()) {
+ // Already warmed up.
+ return
+ }
+ Trace.beginSection("$TAG#warmUp")
+ viewHostAdapter.prepareViewHost(context.resources.configuration)
+ viewHostAdapter.updateView(
+ rootView,
+ WindowManager.LayoutParams(
+ 0 /* width*/,
+ 0 /* height */,
+ TYPE_APPLICATION,
+ FLAG_NOT_FOCUSABLE or FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSPARENT
+ ).apply {
+ setTitle("View root of $TAG#$id")
+ setTrustedOverlay()
+ }
+ )
+ Trace.endSection()
+ }
+
+ override fun updateView(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration,
+ onDrawTransaction: SurfaceControl.Transaction?
+ ) {
+ clearCurrentUpdateJob()
+ updateViewHost(view, attrs, configuration, onDrawTransaction)
+ }
+
+ override fun updateViewAsync(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration
+ ) {
+ clearCurrentUpdateJob()
+ currentUpdateJob = mainScope.launch {
+ updateViewHost(view, attrs, configuration, onDrawTransaction = null)
+ }
+ }
+
+ override fun release(t: SurfaceControl.Transaction) {
+ clearCurrentUpdateJob()
+ viewHostAdapter.release(t)
+ }
+
+ private fun updateViewHost(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration,
+ onDrawTransaction: SurfaceControl.Transaction?
+ ) {
+ viewHostAdapter.prepareViewHost(configuration)
+ onDrawTransaction?.let {
+ viewHostAdapter.applyTransactionOnDraw(it)
+ }
+ rootView.removeAllViews()
+ rootView.addView(view)
+ viewHostAdapter.updateView(rootView, attrs)
+ }
+
+ private fun clearCurrentUpdateJob() {
+ currentUpdateJob?.cancel()
+ currentUpdateJob = null
+ }
+
+ interface Factory {
+ fun create(
+ context: Context,
+ @ShellMainThread mainScope: CoroutineScope,
+ display: Display,
+ id: Int
+ ): ReusableWindowDecorViewHost
+ }
+
+ object DefaultFactory : Factory {
+ override fun create(
+ context: Context,
+ @ShellMainThread mainScope: CoroutineScope,
+ display: Display,
+ id: Int
+ ): ReusableWindowDecorViewHost {
+ return ReusableWindowDecorViewHost(
+ context,
+ mainScope,
+ display,
+ id
+ )
+ }
+ }
+
+ companion object {
+ private const val TAG = "ReusableWindowDecorViewHost"
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapter.kt
new file mode 100644
index 0000000..a54c9ba
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapter.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.content.Context
+import android.content.res.Configuration
+import android.view.AttachedSurfaceControl
+import android.view.Display
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import android.view.WindowlessWindowManager
+import androidx.tracing.Trace
+import com.android.internal.annotations.VisibleForTesting
+typealias SurfaceControlViewHostFactory =
+ (Context, Display, WindowlessWindowManager, String) -> SurfaceControlViewHost
+
+/**
+ * Adapter for a [SurfaceControlViewHost] and its backing [SurfaceControl].
+ *
+ * It does not support swapping the root view added to the VRI of the [SurfaceControlViewHost], and
+ * any attempts to do will throw, which means that once a [View] is added using [updateView], only
+ * its properties and binding may be changed, its children views may be added, removed or changed
+ * and its [WindowManager.LayoutParams] may be changed.
+ */
+class SurfaceControlViewHostAdapter(
+ private val context: Context,
+ private val display: Display,
+ private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory = { c, d, wwm, s ->
+ SurfaceControlViewHost(c, d, wwm, s)
+ }
+) {
+ val rootSurface: SurfaceControl = SurfaceControl.Builder()
+ .setName("SurfaceControlViewHostAdapter surface")
+ .setContainerLayer()
+ .setCallsite("SurfaceControlViewHostAdapter#init")
+ .build()
+
+ private var wwm: WindowlessWindowManager? = null
+ @VisibleForTesting
+ var viewHost: SurfaceControlViewHost? = null
+
+ /** Initialize the [SurfaceControlViewHost] if needed. */
+ fun prepareViewHost(configuration: Configuration) {
+ if (wwm == null) {
+ wwm = WindowlessWindowManager(configuration, rootSurface, null)
+ }
+ requireWindowlessWindowManager().setConfiguration(configuration)
+ if (viewHost == null) {
+ viewHost = surfaceControlViewHostFactory.invoke(
+ context,
+ display,
+ requireWindowlessWindowManager(),
+ "SurfaceControlViewHostAdapter#prepareViewHost"
+ )
+ }
+ }
+
+ /**
+ * Request to apply the transaction atomically with the next draw of the view hierarchy.
+ * See [AttachedSurfaceControl.applyTransactionOnDraw].
+ */
+ fun applyTransactionOnDraw(t: SurfaceControl.Transaction) {
+ requireViewHost().rootSurfaceControl.applyTransactionOnDraw(t)
+ }
+
+ /** Update the view hierarchy of the view host. */
+ fun updateView(view: View, attrs: WindowManager.LayoutParams) {
+ if (requireViewHost().view == null) {
+ Trace.beginSection("SurfaceControlViewHostAdapter#updateView-setView")
+ requireViewHost().setView(view, attrs)
+ Trace.endSection()
+ } else {
+ check(requireViewHost().view == view) { "Changing view is not allowed" }
+ Trace.beginSection("SurfaceControlViewHostAdapter#updateView-relayout")
+ requireViewHost().relayout(attrs)
+ Trace.endSection()
+ }
+ }
+
+ /** Release the view host and remove the backing surface. */
+ fun release(t: SurfaceControl.Transaction) {
+ viewHost?.release()
+ t.remove(rootSurface)
+ }
+
+ /** Whether the view host has had a view hierarchy set. */
+ fun isInitialized(): Boolean = viewHost?.view != null
+
+ private fun requireWindowlessWindowManager(): WindowlessWindowManager {
+ return wwm ?: error("Expected non-null windowless window manager")
+ }
+
+ private fun requireViewHost(): SurfaceControlViewHost {
+ return viewHost ?: error("Expected non-null view host")
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt
similarity index 75%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
copy to libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt
index e3beff7..0df9bfa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewhost/Warmable.kt
@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.wm.shell.windowdecor.viewhost
-package com.android.systemui.qs.panels.domain.interactor
-
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.noopGridConsistencyInteractor by Kosmos.Fixture { NoopGridConsistencyInteractor() }
+/**
+ * An interface for an object that can be warmed up before it's needed.
+ */
+interface Warmable {
+ fun warmUp()
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt
new file mode 100644
index 0000000..f08e50e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper.Corners.LEFT_TOP
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionResizeAndDrag {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val mediaProjectionAppHelper = StartMediaProjectionAppHelper(instrumentation)
+ private val testApp = DesktopModeAppHelper(mediaProjectionAppHelper)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(0)
+ testApp.enterDesktopWithDrag(wmHelper, device)
+ }
+
+ @Test
+ open fun startMediaProjectionAndResize() {
+ mediaProjectionAppHelper.startSingleAppMediaProjection(wmHelper, targetApp)
+
+ with(DesktopModeAppHelper(targetApp)) {
+ val windowRect = wmHelper.getWindowRegion(this).bounds
+ // Set start x-coordinate as center of app header.
+ val startX = windowRect.centerX()
+ val startY = windowRect.top
+
+ dragWindow(startX, startY, endX = startX + 150, endY = startY + 150, wmHelper, device)
+ cornerResize(wmHelper, device, LEFT_TOP, -200, -200)
+ }
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ targetApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt
new file mode 100644
index 0000000..717ea30
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.MailAppHelper
+import com.android.server.wm.flicker.helpers.NewTasksAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionWithMaxDesktopWindows {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val mailApp = MailAppHelper(instrumentation)
+ private val newTasksApp = DesktopModeAppHelper(NewTasksAppHelper(instrumentation))
+ private val imeApp = DesktopModeAppHelper(ImeAppHelper(instrumentation))
+ private val simpleApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+ private val mediaProjectionAppHelper = StartMediaProjectionAppHelper(instrumentation)
+ private val testApp = DesktopModeAppHelper(mediaProjectionAppHelper)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(0)
+ testApp.enterDesktopWithDrag(wmHelper, device)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ // TODO(b/366455106) - handle max task Limit
+ mediaProjectionAppHelper.startSingleAppMediaProjection(wmHelper, targetApp)
+ mailApp.launchViaIntent(wmHelper)
+ simpleApp.launchViaIntent(wmHelper)
+ newTasksApp.launchViaIntent(wmHelper)
+ imeApp.launchViaIntent(wmHelper)
+ }
+
+ @After
+ fun teardown() {
+ mailApp.exit(wmHelper)
+ simpleApp.exit(wmHelper)
+ newTasksApp.exit(wmHelper)
+ imeApp.exit(wmHelper)
+ targetApp.exit(wmHelper)
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt
new file mode 100644
index 0000000..0051952
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.MailAppHelper
+import com.android.server.wm.flicker.helpers.NewTasksAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartScreenMediaProjectionWithMaxDesktopWindows {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0)
+
+ private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation))
+ private val newTasksApp = DesktopModeAppHelper(NewTasksAppHelper(instrumentation))
+ private val imeApp = DesktopModeAppHelper(ImeAppHelper(instrumentation))
+ private val simpleApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+ private val mediaProjectionAppHelper = StartMediaProjectionAppHelper(instrumentation)
+ private val testApp = DesktopModeAppHelper(mediaProjectionAppHelper)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ testApp.enterDesktopWithDrag(wmHelper, device)
+ }
+
+ @Test
+ open fun startMediaProjection() {
+ mediaProjectionAppHelper.startEntireScreenMediaProjection(wmHelper)
+ simpleApp.launchViaIntent(wmHelper)
+ mailApp.launchViaIntent(wmHelper)
+ newTasksApp.launchViaIntent(wmHelper)
+ imeApp.launchViaIntent(wmHelper)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ simpleApp.exit(wmHelper)
+ mailApp.exit(wmHelper)
+ newTasksApp.exit(wmHelper)
+ imeApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp
new file mode 100644
index 0000000..85e6a8d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "WMShellFlickerTestsMediaProjection",
+ defaults: ["WMShellFlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*.kt"],
+ static_libs: [
+ "WMShellFlickerTestsBase",
+ "WMShellScenariosMediaProjection",
+ "WMShellTestUtils",
+ ],
+ data: ["trace_config/*"],
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml
new file mode 100644
index 0000000..74b0daf
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml
@@ -0,0 +1,85 @@
+<!--
+ ~ Copyright (C) 2023 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.wm.shell.flicker">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+ <!-- Read and write traces from external storage -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <!-- Allow the test to write directly to /sdcard/ -->
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+ <!-- Write secure settings -->
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <!-- Capture screen contents -->
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+ <!-- Enable / Disable tracing !-->
+ <uses-permission android:name="android.permission.DUMP" />
+ <!-- Run layers trace -->
+ <uses-permission android:name="android.permission.HARDWARE_TEST"/>
+ <!-- Capture screen recording -->
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
+ <!-- Workaround grant runtime permission exception from b/152733071 -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+ <uses-permission android:name="android.permission.READ_LOGS"/>
+ <!-- Force-stop test apps -->
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
+ <!-- Control test app's media session -->
+ <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
+ <!-- ATM.removeRootTasksWithActivityTypes() -->
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
+ <!-- Enable bubble notification-->
+ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
+ <!-- Allow the test to connect to perfetto trace processor -->
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
+
+ <!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
+ <application android:requestLegacyExternalStorage="true"
+ android:networkSecurityConfig="@xml/network_security_config"
+ android:largeHeap="true">
+ <uses-library android:name="android.test.runner"/>
+
+ <service android:name=".NotificationListener"
+ android:exported="true"
+ android:label="WMShellTestsNotificationListenerService"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService" />
+ </intent-filter>
+ </service>
+
+ <service android:name="com.android.wm.shell.flicker.utils.MediaProjectionService"
+ android:foregroundServiceType="mediaProjection"
+ android:label="WMShellTestsMediaProjectionService"
+ android:enabled="true">
+ </service>
+
+ <!-- (b/197936012) Remove startup provider due to test timeout issue -->
+ <provider
+ android:name="androidx.startup.InitializationProvider"
+ android:authorities="${applicationId}.androidx-startup"
+ tools:node="remove" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker"
+ android:label="WindowManager Shell Flicker Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml
new file mode 100644
index 0000000..40dbbac
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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="Runs WindowManager Shell Flicker Tests {MODULE}">
+ <option name="test-tag" value="FlickerTests"/>
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- disable DeprecatedTargetSdk warning -->
+ <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on"/>
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true"/>
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all"/>
+ <!-- set WM tracing to frame (avoid incomplete states) -->
+ <option name="run-command" value="cmd window tracing frame"/>
+ <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
+ <option name="run-command" value="pm disable com.google.android.internal.betterbug"/>
+ <!-- ensure lock screen mode is swipe -->
+ <option name="run-command" value="locksettings set-disabled false"/>
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command"
+ value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/>
+ <!-- Increase trace size: 20mb for WM and 80mb for SF -->
+ <option name="run-command" value="cmd window tracing size 20480"/>
+ <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/>
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="test-user-token" value="%TEST_USER%"/>
+ <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
+ <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
+ <option name="run-command" value="settings put system show_touches 1"/>
+ <option name="run-command" value="settings put system pointer_location 1"/>
+ <option name="teardown-command"
+ value="settings delete secure show_ime_with_hard_keyboard"/>
+ <option name="teardown-command" value="settings delete system show_touches"/>
+ <option name="teardown-command" value="settings delete system pointer_location"/>
+ <option name="teardown-command"
+ value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/>
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="{MODULE}.apk"/>
+ <option name="test-file-name" value="FlickerTestApp.apk"/>
+ </target_preparer>
+
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file"
+ key="trace_config.textproto"
+ value="/data/misc/perfetto-traces/trace_config.textproto"
+ />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="{PACKAGE}"/>
+ <option name="shell-timeout" value="6600s"/>
+ <option name="test-timeout" value="6000s"/>
+ <option name="hidden-api-checks" value="false"/>
+ <option name="device-listeners" value="android.device.collectors.PerfettoListener"/>
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
+ <option name="instrumentation-arg"
+ key="perfetto_config_file"
+ value="trace_config.textproto"
+ />
+ <option name="instrumentation-arg" key="per_run" value="true"/>
+ <option name="instrumentation-arg" key="perfetto_persist_pid_track" value="true"/>
+ </test>
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.wm.shell.flicker/files"/>
+ <option name="collect-on-run-ended-only" value="true"/>
+ <option name="clean-up" value="true"/>
+ </metrics_collector>
+</configuration>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml
new file mode 100644
index 0000000..4bd9ca0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto
new file mode 100644
index 0000000..9f2e497
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto
@@ -0,0 +1,71 @@
+# Copyright (C) 2023 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.
+
+# proto-message: TraceConfig
+
+# Enable periodic flushing of the trace buffer into the output file.
+write_into_file: true
+
+# Writes the userspace buffer into the file every 1s.
+file_write_period_ms: 2500
+
+# See b/126487238 - we need to guarantee ordering of events.
+flush_period_ms: 30000
+
+# The trace buffers needs to be big enough to hold |file_write_period_ms| of
+# trace data. The trace buffer sizing depends on the number of trace categories
+# enabled and the device activity.
+
+# RSS events
+buffers: {
+ size_kb: 63488
+ fill_policy: RING_BUFFER
+}
+
+data_sources {
+ config {
+ name: "linux.process_stats"
+ target_buffer: 0
+ # polled per-process memory counters and process/thread names.
+ # If you don't want the polled counters, remove the "process_stats_config"
+ # section, but keep the data source itself as it still provides on-demand
+ # thread/process naming for ftrace data below.
+ process_stats_config {
+ scan_all_processes_on_start: true
+ }
+ }
+}
+
+data_sources: {
+ config {
+ name: "linux.ftrace"
+ ftrace_config {
+ ftrace_events: "ftrace/print"
+ ftrace_events: "task/task_newtask"
+ ftrace_events: "task/task_rename"
+ atrace_categories: "ss"
+ atrace_categories: "wm"
+ atrace_categories: "am"
+ atrace_categories: "aidl"
+ atrace_categories: "input"
+ atrace_categories: "binder_driver"
+ atrace_categories: "sched_process_exit"
+ atrace_apps: "com.android.server.wm.flicker.testapp"
+ atrace_apps: "com.android.systemui"
+ atrace_apps: "com.android.wm.shell.flicker.service"
+ atrace_apps: "com.google.android.apps.nexuslauncher"
+ }
+ }
+}
+
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/Android.bp b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/Android.bp
new file mode 100644
index 0000000..997a0af
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library {
+ name: "WMShellScenariosMediaProjection",
+ platform_apis: true,
+ optimize: {
+ enabled: false,
+ },
+ srcs: ["src/**/*.kt"],
+ static_libs: [
+ "WMShellFlickerTestsBase",
+ "WMShellTestUtils",
+ "wm-shell-flicker-utils",
+ "androidx.test.ext.junit",
+ "flickertestapplib",
+ "flickerlib-helpers",
+ "flickerlib-trace_processor_shell",
+ "platform-test-annotations",
+ "wm-flicker-common-app-helpers",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl",
+ ],
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithDisplayRotations.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithDisplayRotations.kt
new file mode 100644
index 0000000..1573b58
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithDisplayRotations.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionWithDisplayRotations {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val targetApp = CalculatorAppHelper(instrumentation)
+ private val mediaProjectionAppHelper = StartMediaProjectionAppHelper(instrumentation)
+ private val testApp = DesktopModeAppHelper(mediaProjectionAppHelper)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(initialRotation.value)
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun startMediaProjectionAndRotate() {
+ mediaProjectionAppHelper.startSingleAppMediaProjection(wmHelper, targetApp)
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+
+ ChangeDisplayOrientationRule.setRotation(Rotation.ROTATION_90)
+ ChangeDisplayOrientationRule.setRotation(Rotation.ROTATION_270)
+ ChangeDisplayOrientationRule.setRotation(Rotation.ROTATION_0)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithDisplayRotations.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithDisplayRotations.kt
new file mode 100644
index 0000000..e80a895
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithDisplayRotations.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartScreenMediaProjectionWithDisplayRotations {
+
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val tapl = LauncherInstrumentation()
+ val wmHelper = WindowManagerStateHelper(instrumentation)
+ val device = UiDevice.getInstance(instrumentation)
+
+ private val initialRotation = Rotation.ROTATION_0
+ private val mediaProjectionAppHelper = StartMediaProjectionAppHelper(instrumentation)
+ private val testApp = DesktopModeAppHelper(mediaProjectionAppHelper)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+ @Before
+ fun setup() {
+ tapl.setEnableRotation(true)
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun startMediaProjectionAndRotate() {
+ mediaProjectionAppHelper.startEntireScreenMediaProjection(wmHelper)
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+
+ ChangeDisplayOrientationRule.setRotation(Rotation.ROTATION_90)
+ ChangeDisplayOrientationRule.setRotation(Rotation.ROTATION_270)
+ ChangeDisplayOrientationRule.setRotation(initialRotation)
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionService.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionService.kt
new file mode 100644
index 0000000..aa4e216
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionService.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.flicker.utils
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.Service
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.drawable.Icon
+import android.os.IBinder
+import android.os.Message
+import android.os.Messenger
+import android.os.RemoteException
+import android.util.Log
+
+class MediaProjectionService : Service() {
+
+ private var mTestBitmap: Bitmap? = null
+
+ private val notificationId: Int = 1
+ private val notificationChannelId: String = "MediaProjectionFlickerTest"
+ private val notificationChannelName = "FlickerMediaProjectionService"
+
+ var mMessenger: Messenger? = null
+
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ mMessenger = intent.extras?.getParcelable(
+ MediaProjectionUtils.EXTRA_MESSENGER, Messenger::class.java)
+ startForeground()
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+ override fun onBind(intent: Intent?): IBinder? = null
+
+ override fun onDestroy() {
+ mTestBitmap?.recycle()
+ mTestBitmap = null
+ sendMessage(MediaProjectionUtils.MSG_SERVICE_DESTROYED)
+ super.onDestroy()
+ }
+
+ private fun createNotificationIcon(): Icon {
+ Log.d(TAG, "createNotification")
+
+ mTestBitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(mTestBitmap!!)
+ canvas.drawColor(Color.BLUE)
+ return Icon.createWithBitmap(mTestBitmap)
+ }
+
+ private fun startForeground() {
+ Log.d(TAG, "startForeground")
+ val channel = NotificationChannel(
+ notificationChannelId,
+ notificationChannelName, NotificationManager.IMPORTANCE_NONE
+ )
+ channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
+
+ val notificationManager: NotificationManager =
+ getSystemService(NotificationManager::class.java)
+ notificationManager.createNotificationChannel(channel)
+
+ val notificationBuilder: Notification.Builder =
+ Notification.Builder(this, notificationChannelId)
+
+ val notification = notificationBuilder.setOngoing(true)
+ .setContentTitle("App is running")
+ .setSmallIcon(createNotificationIcon())
+ .setCategory(Notification.CATEGORY_SERVICE)
+ .setContentText("Context")
+ .build()
+
+ startForeground(notificationId, notification)
+ sendMessage(MediaProjectionUtils.MSG_START_FOREGROUND_DONE)
+ }
+
+ fun sendMessage(what: Int) {
+ Log.d(TAG, "sendMessage")
+ with(Message.obtain()) {
+ this.what = what
+ try {
+ mMessenger!!.send(this)
+ } catch (e: RemoteException) {
+ Log.d(TAG, "Unable to send message", e)
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG: String = "FlickerMediaProjectionService"
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
similarity index 70%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
copy to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
index e3beff7..f9706969 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.qs.panels.domain.interactor
+package com.android.wm.shell.flicker.utils
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.noopGridConsistencyInteractor by Kosmos.Fixture { NoopGridConsistencyInteractor() }
+object MediaProjectionUtils {
+ const val REQUEST_CODE: Int = 99
+ const val MSG_START_FOREGROUND_DONE: Int = 1
+ const val MSG_SERVICE_DESTROYED: Int = 2
+ const val EXTRA_MESSENGER: String = "messenger"
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 10557dd..b47201e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -18,7 +18,9 @@
import android.app.ActivityManager.RecentTaskInfo
import android.app.ActivityManager.RunningTaskInfo
+import android.app.ActivityOptions
import android.app.KeyguardManager
+import android.app.PendingIntent
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
@@ -43,6 +45,7 @@
import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
import android.view.Display.DEFAULT_DISPLAY
+import android.view.DragEvent
import android.view.Gravity
import android.view.SurfaceControl
import android.view.WindowManager
@@ -107,6 +110,7 @@
import com.android.wm.shell.transition.Transitions.TransitionHandler
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
+import java.util.function.Consumer
import java.util.Optional
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
@@ -131,8 +135,8 @@
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.atLeastOnce
-import org.mockito.kotlin.eq
import org.mockito.kotlin.capture
+import org.mockito.kotlin.eq
import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
@@ -1666,6 +1670,36 @@
}
@Test
+ fun handleRequest_fullscreenTask_noTasks_enforceDesktop_freeformDisplay_returnFreeformWCT() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+ tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
+
+ val fullscreenTask = createFullscreenTask()
+ val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+
+ assertNotNull(wct, "should handle request")
+ assertThat(wct.changes[fullscreenTask.token.asBinder()]?.windowingMode)
+ .isEqualTo(WINDOWING_MODE_UNDEFINED)
+ assertThat(wct.hierarchyOps).hasSize(1)
+ wct.assertReorderAt(0, fullscreenTask, toTop = true)
+ }
+
+ @Test
+ fun handleRequest_fullscreenTask_noTasks_enforceDesktop_fullscreenDisplay_returnNull() {
+ assumeTrue(ENABLE_SHELL_TRANSITIONS)
+ whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true)
+ val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!!
+ tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
+
+ val fullscreenTask = createFullscreenTask()
+ val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
+
+ assertThat(wct).isNull()
+ }
+
+ @Test
fun handleRequest_fullscreenTask_freeformNotVisible_returnNull() {
assumeTrue(ENABLE_SHELL_TRANSITIONS)
@@ -2956,6 +2990,8 @@
screenOrientation = SCREEN_ORIENTATION_LANDSCAPE
configuration.windowConfiguration.appBounds = bounds
}
+ appCompatTaskInfo.topActivityLetterboxAppWidth = bounds.width()
+ appCompatTaskInfo.topActivityLetterboxAppHeight = bounds.height()
isResizeable = false
}
@@ -3050,6 +3086,95 @@
assertThat(taskRepository.removeBoundsBeforeMaximize(task.taskId)).isNull()
}
+
+ @Test
+ fun onUnhandledDrag_newFreeformIntent() {
+ testOnUnhandledDrag(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR,
+ PointF(1200f, 700f),
+ Rect(240, 700, 2160, 1900))
+ }
+
+ @Test
+ fun onUnhandledDrag_newFreeformIntentSplitLeft() {
+ testOnUnhandledDrag(DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR,
+ PointF(50f, 700f),
+ Rect(0, 0, 500, 1000))
+ }
+
+ @Test
+ fun onUnhandledDrag_newFreeformIntentSplitRight() {
+ testOnUnhandledDrag(DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR,
+ PointF(2500f, 700f),
+ Rect(500, 0, 1000, 1000))
+ }
+
+ @Test
+ fun onUnhandledDrag_newFullscreenIntent() {
+ testOnUnhandledDrag(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ PointF(1200f, 50f),
+ Rect())
+ }
+
+ /**
+ * Assert that an unhandled drag event launches a PendingIntent with the
+ * windowing mode and bounds we are expecting.
+ */
+ private fun testOnUnhandledDrag(
+ indicatorType: DesktopModeVisualIndicator.IndicatorType,
+ inputCoordinate: PointF,
+ expectedBounds: Rect
+ ) {
+ setUpLandscapeDisplay()
+ val task = setUpFreeformTask()
+ markTaskVisible(task)
+ task.isFocused = true
+ val runningTasks = ArrayList<RunningTaskInfo>()
+ runningTasks.add(task)
+ val spyController = spy(controller)
+ val mockPendingIntent = mock(PendingIntent::class.java)
+ val mockDragEvent = mock(DragEvent::class.java)
+ val mockCallback = mock(Consumer::class.java)
+ val b = SurfaceControl.Builder()
+ b.setName("test surface")
+ val dragSurface = b.build()
+ whenever(shellTaskOrganizer.runningTasks).thenReturn(runningTasks)
+ whenever(mockDragEvent.dragSurface).thenReturn(dragSurface)
+ whenever(mockDragEvent.x).thenReturn(inputCoordinate.x)
+ whenever(mockDragEvent.y).thenReturn(inputCoordinate.y)
+ whenever(multiInstanceHelper.supportsMultiInstanceSplit(anyOrNull())).thenReturn(true)
+ whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
+ doReturn(indicatorType)
+ .whenever(spyController).updateVisualIndicator(
+ eq(task),
+ anyOrNull(),
+ anyOrNull(),
+ anyOrNull(),
+ eq(DesktopModeVisualIndicator.DragStartState.DRAGGED_INTENT)
+ )
+
+ spyController.onUnhandledDrag(
+ mockPendingIntent,
+ mockDragEvent,
+ mockCallback as Consumer<Boolean>
+ )
+ val arg: ArgumentCaptor<WindowContainerTransaction> =
+ ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ var expectedWindowingMode: Int
+ if (indicatorType == DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR) {
+ expectedWindowingMode = WINDOWING_MODE_FULLSCREEN
+ // Fullscreen launches currently use default transitions
+ verify(transitions).startTransition(any(), capture(arg), anyOrNull())
+ } else {
+ expectedWindowingMode = WINDOWING_MODE_FREEFORM
+ // All other launches use a special handler.
+ verify(dragAndDropTransitionHandler).handleDropEvent(capture(arg))
+ }
+ assertThat(ActivityOptions.fromBundle(arg.value.hierarchyOps[0].launchOptions)
+ .launchWindowingMode).isEqualTo(expectedWindowingMode)
+ assertThat(ActivityOptions.fromBundle(arg.value.hierarchyOps[0].launchOptions)
+ .launchBounds).isEqualTo(expectedBounds)
+ }
+
private val desktopWallpaperIntent: Intent
get() = Intent(context, DesktopWallpaperActivity::class.java)
@@ -3114,6 +3239,18 @@
appCompatTaskInfo.isUserFullscreenOverrideEnabled = enableUserFullscreenOverride
appCompatTaskInfo.isSystemFullscreenOverrideEnabled = enableSystemFullscreenOverride
+ if (deviceOrientation == ORIENTATION_LANDSCAPE) {
+ configuration.windowConfiguration.appBounds =
+ Rect(0, 0, DISPLAY_DIMENSION_LONG, DISPLAY_DIMENSION_SHORT)
+ appCompatTaskInfo.topActivityLetterboxAppWidth = DISPLAY_DIMENSION_LONG
+ appCompatTaskInfo.topActivityLetterboxAppHeight = DISPLAY_DIMENSION_SHORT
+ } else {
+ configuration.windowConfiguration.appBounds =
+ Rect(0, 0, DISPLAY_DIMENSION_SHORT, DISPLAY_DIMENSION_LONG)
+ appCompatTaskInfo.topActivityLetterboxAppWidth = DISPLAY_DIMENSION_SHORT
+ appCompatTaskInfo.topActivityLetterboxAppHeight = DISPLAY_DIMENSION_LONG
+ }
+
if (shouldLetterbox) {
appCompatTaskInfo.setHasMinAspectRatioOverride(aspectRatioOverrideApplied)
if (deviceOrientation == ORIENTATION_LANDSCAPE &&
@@ -3130,14 +3267,6 @@
appCompatTaskInfo.topActivityLetterboxAppHeight = 1200
}
}
-
- if (deviceOrientation == ORIENTATION_LANDSCAPE) {
- configuration.windowConfiguration.appBounds =
- Rect(0, 0, DISPLAY_DIMENSION_LONG, DISPLAY_DIMENSION_SHORT)
- } else {
- configuration.windowConfiguration.appBounds =
- Rect(0, 0, DISPLAY_DIMENSION_SHORT, DISPLAY_DIMENSION_LONG)
- }
}
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
runningTasks.add(task)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index 5b02837..497d0e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -18,6 +18,8 @@
import android.window.WindowContainerTransaction
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
@@ -448,6 +450,42 @@
)
}
+ @Test
+ fun startDragToDesktop_aborted_logsDragHoldCancelled() {
+ val transition = startDragToDesktopTransition(defaultHandler, createTask(), dragAnimator)
+
+ defaultHandler.onTransitionConsumed(transition, aborted = true, mock())
+
+ verify(mockInteractionJankMonitor).cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD))
+ verify(mockInteractionJankMonitor, times(0)).cancel(
+ eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE))
+ }
+
+ @Test
+ fun mergeEndDragToDesktop_aborted_logsDragReleaseCancelled() {
+ val task = createTask()
+ val startTransition = startDrag(defaultHandler, task)
+ val endTransition = mock<IBinder>()
+ defaultHandler.onTaskResizeAnimationListener = mock()
+ defaultHandler.mergeAnimation(
+ transition = endTransition,
+ info = createTransitionInfo(
+ type = TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP,
+ draggedTask = task
+ ),
+ t = mock<SurfaceControl.Transaction>(),
+ mergeTarget = startTransition,
+ finishCallback = mock<Transitions.TransitionFinishCallback>()
+ )
+
+ defaultHandler.onTransitionConsumed(endTransition, aborted = true, mock())
+
+ verify(mockInteractionJankMonitor)
+ .cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE))
+ verify(mockInteractionJankMonitor, times(0))
+ .cancel(eq(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD))
+ }
+
private fun startDrag(
handler: DragToDesktopTransitionHandler,
task: RunningTaskInfo = createTask(),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
similarity index 92%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
index 645b296..46b60499 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/SplitDragPolicyTest.java
@@ -30,11 +30,11 @@
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
-import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.SplitDragPolicy.Target.TYPE_SPLIT_TOP;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -72,7 +72,7 @@
import com.android.internal.logging.InstanceId;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
+import com.android.wm.shell.draganddrop.SplitDragPolicy.Target;
import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.After;
@@ -92,7 +92,7 @@
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class DragAndDropPolicyTest extends ShellTestCase {
+public class SplitDragPolicyTest extends ShellTestCase {
@Mock
private Context mContext;
@@ -104,7 +104,7 @@
@Mock
private SplitScreenController mSplitScreenStarter;
@Mock
- private DragAndDropPolicy.Starter mFullscreenStarter;
+ private SplitDragPolicy.Starter mFullscreenStarter;
@Mock
private InstanceId mLoggerSessionId;
@@ -112,7 +112,7 @@
private DisplayLayout mLandscapeDisplayLayout;
private DisplayLayout mPortraitDisplayLayout;
private Insets mInsets;
- private DragAndDropPolicy mPolicy;
+ private SplitDragPolicy mPolicy;
private ClipData mActivityClipData;
private PendingIntent mLaunchableIntentPendingIntent;
@@ -150,7 +150,7 @@
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0);
- mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mFullscreenStarter));
+ mPolicy = spy(new SplitDragPolicy(mContext, mSplitScreenStarter, mFullscreenStarter));
mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
mLaunchableIntentPendingIntent = mock(PendingIntent.class);
when(mLaunchableIntentPendingIntent.getCreatorUserHandle())
@@ -289,7 +289,7 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_FULLSCREEN), null /* hideTaskToken */);
verify(mFullscreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_UNDEFINED), any(), any());
}
@@ -304,12 +304,12 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_LEFT), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
reset(mSplitScreenStarter);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_RIGHT), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
}
@@ -324,12 +324,12 @@
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), null /* hideTaskToken */);
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_TOP), null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_TOP_OR_LEFT), any(), any());
reset(mSplitScreenStarter);
- mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM),
+ mPolicy.onDropped(filterTargetByType(targets, TYPE_SPLIT_BOTTOM),
null /* hideTaskToken */);
verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(),
eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 6ddb678..f3944d5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -256,7 +256,7 @@
when(mMockPipDisplayLayoutState.getDisplayLayout()).thenReturn(mMockDisplayLayout1);
when(mMockDisplayController.getDisplayLayout(displayId)).thenReturn(mMockDisplayLayout2);
- when(mMockPipTaskOrganizer.isInPip()).thenReturn(true);
+ when(mMockPipTransitionState.hasEnteredPip()).thenReturn(true);
mPipController.mDisplaysChangedListener.onDisplayConfigurationChanged(
displayId, new Configuration());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 7937a84..61a725f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -557,7 +557,7 @@
mMainExecutor.flushAll();
// Takeover shouldn't happen when the flag is disabled.
- setFlagsRule.disableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY);
+ setFlagsRule.disableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED);
IBinder transitToken = new Binder();
transitions.requestStartTransition(transitToken,
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
@@ -572,7 +572,7 @@
verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any());
// Takeover should happen when the flag is enabled.
- setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY);
+ setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED);
transitions.requestStartTransition(transitToken,
new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
info = new TransitionInfoBuilder(TRANSIT_OPEN)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index a17d08d..a18fbf0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -316,7 +316,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @DisableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX)
fun testCreateAndDisposeEventReceiver() {
val decor = createOpenTaskDecoration(windowingMode = WINDOWING_MODE_FREEFORM)
desktopModeWindowDecorViewModel.destroyWindowDecoration(decor.mTaskInfo)
@@ -326,7 +326,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @DisableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX)
fun testEventReceiversOnMultipleDisplays() {
val secondaryDisplay = createVirtualDisplay() ?: return
val secondaryDisplayId = secondaryDisplay.display.displayId
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 7b68ddf..dff42da 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -107,6 +107,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -228,6 +229,8 @@
mTestableContext = new TestableContext(mContext);
mTestableContext.ensureTestableResources();
mContext.setMockPackageManager(mMockPackageManager);
+ when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any()))
+ .thenReturn(false);
when(mMockPackageManager.getApplicationLabel(any())).thenReturn("applicationLabel");
final ActivityInfo activityInfo = new ActivityInfo();
activityInfo.applicationInfo = new ApplicationInfo();
@@ -235,8 +238,8 @@
final Display defaultDisplay = mock(Display.class);
doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY);
doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt());
- when(mMockHandleMenuFactory.create(any(), any(), anyInt(), any(), any(),
- any(), anyBoolean(), anyBoolean(), any(), anyInt(), anyInt(), anyInt()))
+ when(mMockHandleMenuFactory.create(any(), any(), anyInt(), any(), any(), any(),
+ anyBoolean(), anyBoolean(), anyBoolean(), any(), anyInt(), anyInt(), anyInt()))
.thenReturn(mMockHandleMenu);
when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any())).thenReturn(false);
when(mMockWindowDecorViewHostSupplier.acquire(any(), eq(defaultDisplay)))
@@ -404,7 +407,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @DisableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX)
public void updateRelayoutParams_fullscreen_inputChannelNotNeeded() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -421,7 +424,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @DisableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX)
public void updateRelayoutParams_multiwindow_inputChannelNotNeeded() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
@@ -561,6 +564,7 @@
}
@Test
+ @Ignore("TODO(b/367235906): Due to MONITOR_INPUT permission error")
public void relayout_freeformTask_appliesTransactionOnDraw() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo));
@@ -744,6 +748,7 @@
any(),
any(),
any(),
+ any(),
openInBrowserCaptor.capture(),
any(),
any()
@@ -771,6 +776,7 @@
any(),
any(),
any(),
+ any(),
openInBrowserCaptor.capture(),
any(),
any()
@@ -821,6 +827,7 @@
any(),
any(),
any(),
+ any(),
closeClickListener.capture(),
any()
);
@@ -833,7 +840,8 @@
private void verifyHandleMenuCreated(@Nullable Uri uri) {
verify(mMockHandleMenuFactory).create(any(), any(), anyInt(), any(), any(),
- any(), anyBoolean(), anyBoolean(), eq(uri), anyInt(), anyInt(), anyInt());
+ any(), anyBoolean(), anyBoolean(), anyBoolean(), eq(uri), anyInt(),
+ anyInt(), anyInt());
}
private void createMaximizeMenu(DesktopModeWindowDecoration decoration, MaximizeMenu menu) {
@@ -932,7 +940,7 @@
}
private void createHandleMenu(@NonNull DesktopModeWindowDecoration decor) {
- decor.createHandleMenu();
+ decor.createHandleMenu(false);
// Call DesktopModeWindowDecoration#onAssistContentReceived because decor waits to receive
// {@link AssistContent} before creating the menu
decor.onAssistContentReceived(mAssistContent);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index 1f33ae6..24f6bec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -39,6 +39,7 @@
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Before
@@ -105,6 +106,7 @@
initializeTaskInfo()
mockWindowDecoration.mDisplay = mockDisplay
mockWindowDecoration.mDecorWindowContext = mockContext
+ mockWindowDecoration.mTaskInfo.isResizeable = true
whenever(mockContext.getResources()).thenReturn(mockResources)
whenever(mockWindowDecoration.mDecorWindowContext.resources).thenReturn(mockResources)
whenever(mockResources.getDimensionPixelSize(R.dimen.desktop_mode_minimum_window_width))
@@ -164,6 +166,60 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_SCALED_RESIZING)
+ fun testChangeBounds_unresizeableApp_heightLessThanMin_resetToStartingBounds() {
+ mockWindowDecoration.mTaskInfo.isResizeable = false
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
+
+ // Resize to width of 95px and height of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ assertFalse(
+ DragPositioningCallbackUtility.changeBounds(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController,
+ mockWindowDecoration
+ )
+ )
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_SCALED_RESIZING)
+ fun testChangeBounds_unresizeableApp_widthLessThanMin_resetToStartingBounds() {
+ mockWindowDecoration.mTaskInfo.isResizeable = false
+ val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
+
+ // Resize to height of 95px and width of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+
+ assertFalse(
+ DragPositioningCallbackUtility.changeBounds(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController,
+ mockWindowDecoration
+ )
+ )
+
+
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+
+ @Test
fun testChangeBoundsDoesNotChangeHeightWhenNegative() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
val repositionTaskBounds = Rect(STARTING_BOUNDS)
@@ -317,6 +373,34 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_WINDOWING_SCALED_RESIZING)
+ fun testChangeBounds_unresizeableApp_beyondStableBounds_resetToStartingBounds() {
+ mockWindowDecoration.mTaskInfo.isResizeable = false
+ val startingPoint = PointF(
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat()
+ )
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
+
+ // Resize to beyond stable bounds.
+ val newX = STARTING_BOUNDS.right.toFloat() + STABLE_BOUNDS.width()
+ val newY = STARTING_BOUNDS.bottom.toFloat() + STABLE_BOUNDS.height()
+
+ val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
+ assertFalse(
+ DragPositioningCallbackUtility.changeBounds(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta, mockDisplayController,
+ mockWindowDecoration
+ )
+ )
+ assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
+ assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
+ assertThat(repositionTaskBounds.right).isEqualTo(STARTING_BOUNDS.right)
+ assertThat(repositionTaskBounds.bottom).isEqualTo(STARTING_BOUNDS.bottom)
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeLessThanMin_shouldNotChangeBounds() {
doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(mockContext) }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt
new file mode 100644
index 0000000..ce17c1d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FixedAspectRatioTaskPositionerDecoratorTests.kt
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor
+
+import android.app.ActivityManager
+import android.graphics.PointF
+import android.graphics.Rect
+import android.util.MathUtils.abs
+import android.util.MathUtils.max
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CtrlType
+import com.google.common.truth.Truth.assertThat
+import com.google.testing.junit.testparameterinjector.TestParameter
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
+import kotlin.math.min
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.never
+
+/**
+ * Tests for the [FixedAspectRatioTaskPositionerDecorator], written in parameterized form to check
+ * decorators behaviour for different variations of drag actions.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:FixedAspectRatioTaskPositionerDecoratorTests
+ */
+@SmallTest
+@RunWith(TestParameterInjector::class)
+class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){
+ @Mock
+ private lateinit var mockDesktopWindowDecoration: DesktopModeWindowDecoration
+ @Mock
+ private lateinit var mockTaskPositioner: VeiledResizeTaskPositioner
+
+ private lateinit var decoratedTaskPositioner: FixedAspectRatioTaskPositionerDecorator
+
+ @Before
+ fun setUp() {
+ mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ isResizeable = false
+ configuration.windowConfiguration.setBounds(PORTRAIT_BOUNDS)
+ }
+ doReturn(PORTRAIT_BOUNDS).`when`(mockTaskPositioner).onDragPositioningStart(
+ any(), any(), any())
+ doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningMove(any(), any())
+ doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningEnd(any(), any())
+ decoratedTaskPositioner = spy(
+ FixedAspectRatioTaskPositionerDecorator(
+ mockDesktopWindowDecoration, mockTaskPositioner)
+ )
+ }
+
+ @Test
+ fun testOnDragPositioningStart_noAdjustment(
+ @TestParameter testCase: ResizeableOrNotResizingTestCases
+ ) {
+ val originalX = 0f
+ val originalY = 0f
+ mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ isResizeable = testCase.isResizeable
+ }
+
+ decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalY)
+
+ val capturedValues = getLatestOnStartArguments()
+ assertThat(capturedValues.ctrlType).isEqualTo(testCase.ctrlType)
+ assertThat(capturedValues.x).isEqualTo(originalX)
+ assertThat(capturedValues.y).isEqualTo(originalY)
+ }
+
+ @Test
+ fun testOnDragPositioningStart_cornerResize_noAdjustment(
+ @TestParameter testCase: CornerResizeStartTestCases
+ ) {
+ val originalX = 0f
+ val originalY = 0f
+
+ decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalY)
+
+ val capturedValues = getLatestOnStartArguments()
+ assertThat(capturedValues.ctrlType).isEqualTo(testCase.ctrlType)
+ assertThat(capturedValues.x).isEqualTo(originalX)
+ assertThat(capturedValues.y).isEqualTo(originalY)
+ }
+
+ @Test
+ fun testOnDragPositioningStart_edgeResize_ctrlTypeAdjusted(
+ @TestParameter testCase: EdgeResizeStartTestCases, @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getEdgeStartingPoint(
+ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ val adjustedCtrlType = testCase.ctrlType + testCase.additionalEdgeCtrlType
+ val capturedValues = getLatestOnStartArguments()
+ assertThat(capturedValues.ctrlType).isEqualTo(adjustedCtrlType)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y)
+ }
+
+ @Test
+ fun testOnDragPositioningMove_noAdjustment(
+ @TestParameter testCase: ResizeableOrNotResizingTestCases
+ ) {
+ val originalX = 0f
+ val originalY = 0f
+ decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalX)
+ mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ isResizeable = testCase.isResizeable
+ }
+
+ decoratedTaskPositioner.onDragPositioningMove(
+ originalX + SMALL_DELTA, originalY + SMALL_DELTA)
+
+ val capturedValues = getLatestOnMoveArguments()
+ assertThat(capturedValues.x).isEqualTo(originalX + SMALL_DELTA)
+ assertThat(capturedValues.y).isEqualTo(originalY + SMALL_DELTA)
+ }
+
+ @Test
+ fun testOnDragPositioningMove_cornerResize_invalidRegion_noResize(
+ @TestParameter testCase: InvalidCornerResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ val updatedBounds = decoratedTaskPositioner.onDragPositioningMove(
+ startingPoint.x + testCase.dragDelta.x,
+ startingPoint.y + testCase.dragDelta.y)
+
+ verify(mockTaskPositioner, never()).onDragPositioningMove(any(), any())
+ assertThat(updatedBounds).isEqualTo(startingBounds)
+ }
+
+
+ @Test
+ fun testOnDragPositioningMove_cornerResize_validRegion_resizeToAdjustedCoordinates(
+ @TestParameter testCase: ValidCornerResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningMove(
+ startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y)
+
+ val adjustedDragDelta = calculateAdjustedDelta(
+ testCase.ctrlType, testCase.dragDelta, orientation)
+ val capturedValues = getLatestOnMoveArguments()
+ val absChangeX = abs(capturedValues.x - startingPoint.x)
+ val absChangeY = abs(capturedValues.y - startingPoint.y)
+ val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y)
+ assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO)
+ }
+
+ @Test
+ fun testOnDragPositioningMove_edgeResize_resizeToAdjustedCoordinates(
+ @TestParameter testCase: EdgeResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getEdgeStartingPoint(
+ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningMove(
+ startingPoint.x + testCase.dragDelta.x,
+ startingPoint.y + testCase.dragDelta.y)
+
+ val adjustedDragDelta = calculateAdjustedDelta(
+ testCase.ctrlType + testCase.additionalEdgeCtrlType,
+ testCase.dragDelta,
+ orientation)
+ val capturedValues = getLatestOnMoveArguments()
+ val absChangeX = abs(capturedValues.x - startingPoint.x)
+ val absChangeY = abs(capturedValues.y - startingPoint.y)
+ val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y)
+ assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO)
+ }
+
+ @Test
+ fun testOnDragPositioningEnd_noAdjustment(
+ @TestParameter testCase: ResizeableOrNotResizingTestCases
+ ) {
+ val originalX = 0f
+ val originalY = 0f
+ decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, originalX, originalX)
+ mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
+ isResizeable = testCase.isResizeable
+ }
+
+ decoratedTaskPositioner.onDragPositioningEnd(
+ originalX + SMALL_DELTA, originalY + SMALL_DELTA)
+
+ val capturedValues = getLatestOnEndArguments()
+ assertThat(capturedValues.x).isEqualTo(originalX + SMALL_DELTA)
+ assertThat(capturedValues.y).isEqualTo(originalY + SMALL_DELTA)
+ }
+
+ @Test
+ fun testOnDragPositioningEnd_cornerResize_invalidRegion_endsAtPreviousValidPoint(
+ @TestParameter testCase: InvalidCornerResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningEnd(
+ startingPoint.x + testCase.dragDelta.x,
+ startingPoint.y + testCase.dragDelta.y)
+
+ val capturedValues = getLatestOnEndArguments()
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y)
+ }
+
+ @Test
+ fun testOnDragPositioningEnd_cornerResize_validRegion_endAtAdjustedCoordinates(
+ @TestParameter testCase: ValidCornerResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningEnd(
+ startingPoint.x + testCase.dragDelta.x, startingPoint.y + testCase.dragDelta.y)
+
+ val adjustedDragDelta = calculateAdjustedDelta(
+ testCase.ctrlType, testCase.dragDelta, orientation)
+ val capturedValues = getLatestOnEndArguments()
+ val absChangeX = abs(capturedValues.x - startingPoint.x)
+ val absChangeY = abs(capturedValues.y - startingPoint.y)
+ val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y)
+ assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO)
+ }
+
+ @Test
+ fun testOnDragPositioningEnd_edgeResize_endAtAdjustedCoordinates(
+ @TestParameter testCase: EdgeResizeTestCases,
+ @TestParameter orientation: Orientation
+ ) {
+ val startingBounds = getAndMockBounds(orientation)
+ val startingPoint = getEdgeStartingPoint(
+ testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds)
+
+ decoratedTaskPositioner.onDragPositioningStart(
+ testCase.ctrlType, startingPoint.x, startingPoint.y)
+
+ decoratedTaskPositioner.onDragPositioningEnd(
+ startingPoint.x + testCase.dragDelta.x,
+ startingPoint.y + testCase.dragDelta.y)
+
+ val adjustedDragDelta = calculateAdjustedDelta(
+ testCase.ctrlType + testCase.additionalEdgeCtrlType,
+ testCase.dragDelta,
+ orientation)
+ val capturedValues = getLatestOnEndArguments()
+ val absChangeX = abs(capturedValues.x - startingPoint.x)
+ val absChangeY = abs(capturedValues.y - startingPoint.y)
+ val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY)
+ assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x)
+ assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y)
+ assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO)
+ }
+
+ /**
+ * Returns the most recent arguments passed to the `.onPositioningStart()` of the
+ * [mockTaskPositioner].
+ */
+ private fun getLatestOnStartArguments(): CtrlCoordinateCapture {
+ val captorCtrlType = argumentCaptor<Int>()
+ val captorCoordinates = argumentCaptor<Float>()
+ verify(mockTaskPositioner).onDragPositioningStart(
+ captorCtrlType.capture(), captorCoordinates.capture(), captorCoordinates.capture())
+
+ return CtrlCoordinateCapture(captorCtrlType.firstValue, captorCoordinates.firstValue,
+ captorCoordinates.secondValue)
+ }
+
+ /**
+ * Returns the most recent arguments passed to the `.onPositioningMove()` of the
+ * [mockTaskPositioner].
+ */
+ private fun getLatestOnMoveArguments(): PointF {
+ val captorCoordinates = argumentCaptor<Float>()
+ verify(mockTaskPositioner).onDragPositioningMove(
+ captorCoordinates.capture(), captorCoordinates.capture())
+
+ return PointF(captorCoordinates.firstValue, captorCoordinates.secondValue)
+ }
+
+ /**
+ * Returns the most recent arguments passed to the `.onPositioningEnd()` of the
+ * [mockTaskPositioner].
+ */
+ private fun getLatestOnEndArguments(): PointF {
+ val captorCoordinates = argumentCaptor<Float>()
+ verify(mockTaskPositioner).onDragPositioningEnd(
+ captorCoordinates.capture(), captorCoordinates.capture())
+
+ return PointF(captorCoordinates.firstValue, captorCoordinates.secondValue)
+ }
+
+ /**
+ * Mocks the app bounds to correspond with a given orientation and returns the mocked bounds.
+ */
+ private fun getAndMockBounds(orientation: Orientation): Rect {
+ val mockBounds = if (orientation.isPortrait) PORTRAIT_BOUNDS else LANDSCAPE_BOUNDS
+ doReturn(mockBounds).`when`(mockTaskPositioner).onDragPositioningStart(
+ any(), any(), any())
+ doReturn(mockBounds).`when`(decoratedTaskPositioner).getBounds(any())
+ return mockBounds
+ }
+
+ /**
+ * Calculates the corner point a given drag action should start from, based on the [ctrlType],
+ * given the [startingBounds].
+ */
+ private fun getCornerStartingPoint(@CtrlType ctrlType: Int, startingBounds: Rect): PointF {
+ return when (ctrlType) {
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT ->
+ PointF(startingBounds.right.toFloat(), startingBounds.bottom.toFloat())
+
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT ->
+ PointF(startingBounds.left.toFloat(), startingBounds.bottom.toFloat())
+
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT ->
+ PointF(startingBounds.right.toFloat(), startingBounds.top.toFloat())
+ // CTRL_TYPE_TOP + CTRL_TYPE_LEFT
+ else ->
+ PointF(startingBounds.left.toFloat(), startingBounds.top.toFloat())
+ }
+ }
+
+ /**
+ * Calculates the point along an edge the edge resize should start from, based on the starting
+ * edge ([edgeCtrlType]) and the additional edge we expect to resize ([additionalEdgeCtrlType]),
+ * given the [startingBounds].
+ */
+ private fun getEdgeStartingPoint(
+ @CtrlType edgeCtrlType: Int, @CtrlType additionalEdgeCtrlType: Int, startingBounds: Rect
+ ): PointF {
+ val simulatedCorner = getCornerStartingPoint(
+ edgeCtrlType + additionalEdgeCtrlType, startingBounds)
+ when (additionalEdgeCtrlType) {
+ CTRL_TYPE_TOP -> {
+ simulatedCorner.offset(0f, -SMALL_DELTA)
+ return simulatedCorner
+ }
+ CTRL_TYPE_BOTTOM -> {
+ simulatedCorner.offset(0f, SMALL_DELTA)
+ return simulatedCorner
+ }
+ CTRL_TYPE_LEFT -> {
+ simulatedCorner.offset(SMALL_DELTA, 0f)
+ return simulatedCorner
+ }
+ // CTRL_TYPE_RIGHT
+ else -> {
+ simulatedCorner.offset(-SMALL_DELTA, 0f)
+ return simulatedCorner
+ }
+ }
+ }
+
+ /**
+ * Calculates the adjustments to the drag delta we expect for a given action and orientation.
+ */
+ private fun calculateAdjustedDelta(
+ @CtrlType ctrlType: Int, delta: PointF, orientation: Orientation
+ ): PointF {
+ if ((abs(delta.x) < abs(delta.y) && delta.x != 0f) || delta.y == 0f) {
+ // Only respect x delta if it's less than y delta but non-zero (i.e there is a change
+ // in x to be applied), or if the y delta is zero (i.e there is no change in y to be
+ // applied).
+ val adjustedY = if (orientation.isPortrait)
+ delta.x * STARTING_ASPECT_RATIO else
+ delta.x / STARTING_ASPECT_RATIO
+ if (ctrlType.isBottomRightOrTopLeftCorner()) {
+ return PointF(delta.x, adjustedY)
+ }
+ return PointF(delta.x, -adjustedY)
+ }
+ // Respect y delta.
+ val adjustedX = if (orientation.isPortrait)
+ delta.y / STARTING_ASPECT_RATIO else
+ delta.y * STARTING_ASPECT_RATIO
+ if (ctrlType.isBottomRightOrTopLeftCorner()) {
+ return PointF(adjustedX, delta.y)
+ }
+ return PointF(-adjustedX, delta.y)
+ }
+
+ private fun @receiver:CtrlType Int.isBottomRightOrTopLeftCorner(): Boolean {
+ return this == CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT || this == CTRL_TYPE_TOP + CTRL_TYPE_LEFT
+ }
+
+ private inner class CtrlCoordinateCapture(ctrl: Int, xValue: Float, yValue: Float) {
+ var ctrlType = ctrl
+ var x = xValue
+ var y = yValue
+ }
+
+ companion object {
+ private val PORTRAIT_BOUNDS = Rect(100, 100, 200, 400)
+ private val LANDSCAPE_BOUNDS = Rect(100, 100, 400, 200)
+ private val STARTING_ASPECT_RATIO = PORTRAIT_BOUNDS.height() / PORTRAIT_BOUNDS.width()
+ private const val LARGE_DELTA = 50f
+ private const val SMALL_DELTA = 30f
+
+ enum class Orientation(
+ val isPortrait: Boolean
+ ) {
+ PORTRAIT (true),
+ LANDSCAPE (false)
+ }
+
+ enum class ResizeableOrNotResizingTestCases(
+ val ctrlType: Int,
+ val isResizeable: Boolean
+ ) {
+ NotResizing (CTRL_TYPE_UNDEFINED, false),
+ Resizeable (CTRL_TYPE_RIGHT, true)
+ }
+
+ /**
+ * Tests cases for the start of a corner resize.
+ * @param ctrlType the control type of the corner the resize is initiated on.
+ */
+ enum class CornerResizeStartTestCases(
+ val ctrlType: Int
+ ) {
+ BottomRightCorner (CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT),
+ BottomLeftCorner (CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT),
+ TopRightCorner (CTRL_TYPE_TOP + CTRL_TYPE_RIGHT),
+ TopLeftCorner (CTRL_TYPE_TOP + CTRL_TYPE_LEFT)
+ }
+
+ /**
+ * Tests cases for the moving and ending of a invalid corner resize. Where the compass point
+ * (e.g `SouthEast`) represents the direction of the drag.
+ * @param ctrlType the control type of the corner the resize is initiated on.
+ * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s
+ * corresponding corner point. Represented as a combination a different signed small and
+ * large deltas which correspond to the direction/angle of drag.
+ */
+ enum class InvalidCornerResizeTestCases(
+ val ctrlType: Int,
+ val dragDelta: PointF
+ ) {
+ BottomRightCornerNorthEastDrag (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(LARGE_DELTA, -LARGE_DELTA)),
+ BottomRightCornerSouthWestDrag (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(-LARGE_DELTA, LARGE_DELTA)),
+ TopLeftCornerNorthEastDrag (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(LARGE_DELTA, -LARGE_DELTA)),
+ TopLeftCornerSouthWestDrag (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(-LARGE_DELTA, LARGE_DELTA)),
+ BottomLeftCornerSouthEastDrag (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(LARGE_DELTA, LARGE_DELTA)),
+ BottomLeftCornerNorthWestDrag (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(-LARGE_DELTA, -LARGE_DELTA)),
+ TopRightCornerSouthEastDrag (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(LARGE_DELTA, LARGE_DELTA)),
+ TopRightCornerNorthWestDrag (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(-LARGE_DELTA, -LARGE_DELTA)),
+ }
+
+ /**
+ * Tests cases for the moving and ending of a valid corner resize. Where the compass point
+ * (e.g `SouthEast`) represents the direction of the drag, followed by the expected
+ * behaviour in that direction (i.e `RespectY` means the y delta will be respected whereas
+ * `RespectX` means the x delta will be respected).
+ * @param ctrlType the control type of the corner the resize is initiated on.
+ * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s
+ * corresponding corner point. Represented as a combination a different signed small and
+ * large deltas which correspond to the direction/angle of drag.
+ */
+ enum class ValidCornerResizeTestCases(
+ val ctrlType: Int,
+ val dragDelta: PointF,
+ ) {
+ BottomRightCornerSouthEastDragRespectY (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(+LARGE_DELTA, SMALL_DELTA)),
+ BottomRightCornerSouthEastDragRespectX (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(SMALL_DELTA, LARGE_DELTA)),
+ BottomRightCornerNorthWestDragRespectY (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(-LARGE_DELTA, -SMALL_DELTA)),
+ BottomRightCornerNorthWestDragRespectX (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT,
+ PointF(-SMALL_DELTA, -LARGE_DELTA)),
+ TopLeftCornerSouthEastDragRespectY (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(LARGE_DELTA, SMALL_DELTA)),
+ TopLeftCornerSouthEastDragRespectX (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(SMALL_DELTA, LARGE_DELTA)),
+ TopLeftCornerNorthWestDragRespectY (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(-LARGE_DELTA, -SMALL_DELTA)),
+ TopLeftCornerNorthWestDragRespectX (
+ CTRL_TYPE_TOP + CTRL_TYPE_LEFT,
+ PointF(-SMALL_DELTA, -LARGE_DELTA)),
+ BottomLeftCornerSouthWestDragRespectY (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(-LARGE_DELTA, SMALL_DELTA)),
+ BottomLeftCornerSouthWestDragRespectX (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(-SMALL_DELTA, LARGE_DELTA)),
+ BottomLeftCornerNorthEastDragRespectY (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(LARGE_DELTA, -SMALL_DELTA)),
+ BottomLeftCornerNorthEastDragRespectX (
+ CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT,
+ PointF(SMALL_DELTA, -LARGE_DELTA)),
+ TopRightCornerSouthWestDragRespectY (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(-LARGE_DELTA, SMALL_DELTA)),
+ TopRightCornerSouthWestDragRespectX (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(-SMALL_DELTA, LARGE_DELTA)),
+ TopRightCornerNorthEastDragRespectY (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(LARGE_DELTA, -SMALL_DELTA)),
+ TopRightCornerNorthEastDragRespectX (
+ CTRL_TYPE_TOP + CTRL_TYPE_RIGHT,
+ PointF(+SMALL_DELTA, -LARGE_DELTA))
+ }
+
+ /**
+ * Tests cases for the start of an edge resize.
+ * @param ctrlType the control type of the edge the resize is initiated on.
+ * @param additionalEdgeCtrlType the expected additional edge to be included in the ctrl
+ * type.
+ */
+ enum class EdgeResizeStartTestCases(
+ val ctrlType: Int,
+ val additionalEdgeCtrlType: Int
+ ) {
+ BottomOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_BOTTOM),
+ TopOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_TOP),
+ BottomOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_BOTTOM),
+ TopOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_TOP),
+ RightOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_RIGHT),
+ LeftOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_LEFT),
+ RightOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_RIGHT),
+ LeftOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_LEFT)
+ }
+
+ /**
+ * Tests cases for the moving and ending of an edge resize.
+ * @param ctrlType the control type of the edge the resize is initiated on.
+ * @param additionalEdgeCtrlType the expected additional edge to be included in the ctrl
+ * type.
+ * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s
+ * corresponding edge point. Represented as a combination a different signed small and
+ * large deltas which correspond to the direction/angle of drag.
+ */
+ enum class EdgeResizeTestCases(
+ val ctrlType: Int,
+ val additionalEdgeCtrlType: Int,
+ val dragDelta: PointF
+ ) {
+ BottomOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_BOTTOM, PointF(-SMALL_DELTA, 0f)),
+ TopOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_TOP, PointF(-SMALL_DELTA, 0f)),
+ BottomOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_BOTTOM, PointF(SMALL_DELTA, 0f)),
+ TopOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, PointF(SMALL_DELTA, 0f)),
+ RightOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_RIGHT, PointF(0f, -SMALL_DELTA)),
+ LeftOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_LEFT, PointF(0f, -SMALL_DELTA)),
+ RightOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_RIGHT, PointF(0f, SMALL_DELTA)),
+ LeftOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_LEFT, PointF(0f, SMALL_DELTA))
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 3a3e965..7543fed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -121,6 +121,7 @@
displayId = DISPLAY_ID
configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
configuration.windowConfiguration.displayRotation = ROTATION_90
+ isResizeable = true
}
`when`(mockWindowDecoration.calculateValidDragArea()).thenReturn(VALID_DRAG_AREA)
mockWindowDecoration.mDisplay = mockDisplay
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
index 100abbb..cabd472 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt
@@ -134,7 +134,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @EnableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX)
fun testFullscreenMenuUsesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_FULLSCREEN, SPLIT_POSITION_UNDEFINED)
val handleMenu = createAndShowHandleMenu(SPLIT_POSITION_UNDEFINED)
@@ -146,7 +146,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @EnableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX)
fun testFreeformMenu_usesViewHostViewContainer() {
createTaskInfo(WINDOWING_MODE_FREEFORM, SPLIT_POSITION_UNDEFINED)
handleMenu = createAndShowHandleMenu(SPLIT_POSITION_UNDEFINED)
@@ -157,7 +157,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @EnableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX)
fun testSplitLeftMenu_usesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, SPLIT_POSITION_TOP_OR_LEFT)
handleMenu = createAndShowHandleMenu(SPLIT_POSITION_TOP_OR_LEFT)
@@ -172,7 +172,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_ADDITIONAL_WINDOWS_ABOVE_STATUS_BAR)
+ @EnableFlags(Flags.FLAG_ENABLE_HANDLE_INPUT_FIX)
fun testSplitRightMenu_usesSystemViewContainer() {
createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, SPLIT_POSITION_BOTTOM_OR_RIGHT)
handleMenu = createAndShowHandleMenu(SPLIT_POSITION_BOTTOM_OR_RIGHT)
@@ -236,11 +236,11 @@
val handleMenu = HandleMenu(mockDesktopWindowDecoration,
WindowManagerWrapper(mockWindowManager),
layoutId, appIcon, appName, splitScreenController, shouldShowWindowingPill = true,
- shouldShowNewWindowButton = true,
+ shouldShowNewWindowButton = true, shouldShowManageWindowsButton = false,
null /* openInBrowserLink */, captionWidth = HANDLE_WIDTH, captionHeight = 50,
captionX = captionX
)
- handleMenu.show(mock(), mock(), mock(), mock(), mock(), mock(), mock())
+ handleMenu.show(mock(), mock(), mock(), mock(), mock(), mock(), mock(), mock())
return handleMenu
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 6ae16ed..7784af6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -141,6 +141,7 @@
displayId = DISPLAY_ID
configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
configuration.windowConfiguration.displayRotation = ROTATION_90
+ isResizeable = true
}
`when`(mockDesktopWindowDecoration.calculateValidDragArea()).thenReturn(VALID_DRAG_AREA)
mockDesktopWindowDecoration.mDisplay = mockDisplay
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
index 1b2ce9e..1b0b7d9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/DefaultWindowDecorViewHostTest.kt
@@ -18,7 +18,6 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.SurfaceControl
-import android.view.SurfaceControlViewHost
import android.view.View
import android.view.WindowManager
import androidx.test.filters.SmallTest
@@ -28,7 +27,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
-import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@@ -59,54 +57,8 @@
onDrawTransaction = null
)
- assertThat(windowDecorViewHost.viewHost).isNotNull()
- assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
- }
-
- @Test
- fun updateView_alreadyLaidOut_relayouts() = runTest {
- val windowDecorViewHost = createDefaultViewHost()
- val view = View(context)
- windowDecorViewHost.updateView(
- view = view,
- attrs = WindowManager.LayoutParams(100, 100),
- configuration = context.resources.configuration,
- onDrawTransaction = null
- )
-
- val otherParams = WindowManager.LayoutParams(200, 200)
- windowDecorViewHost.updateView(
- view = view,
- attrs = otherParams,
- configuration = context.resources.configuration,
- onDrawTransaction = null
- )
-
- assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(view)
- assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
- .isEqualTo(otherParams.width)
- }
-
- @Test
- fun updateView_replacingView_throws() = runTest {
- val windowDecorViewHost = createDefaultViewHost()
- val view = View(context)
- windowDecorViewHost.updateView(
- view = view,
- attrs = WindowManager.LayoutParams(100, 100),
- configuration = context.resources.configuration,
- onDrawTransaction = null
- )
-
- val otherView = View(context)
- assertThrows(Exception::class.java) {
- windowDecorViewHost.updateView(
- view = otherView,
- attrs = WindowManager.LayoutParams(100, 100),
- configuration = context.resources.configuration,
- onDrawTransaction = null
- )
- }
+ assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isTrue()
+ assertThat(windowDecorViewHost.view()).isEqualTo(view)
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -125,7 +77,7 @@
)
// No view host yet, since the coroutine hasn't run.
- assertThat(windowDecorViewHost.viewHost).isNull()
+ assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isFalse()
windowDecorViewHost.updateView(
view = syncView,
@@ -137,14 +89,13 @@
// Would run coroutine if it hadn't been cancelled.
advanceUntilIdle()
- assertThat(windowDecorViewHost.viewHost).isNotNull()
- assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
+ assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isTrue()
+ assertThat(windowDecorViewHost.view()).isNotNull()
// View host view/attrs should match the ones from the sync call, plus, since the
// sync/async were made with different views, if the job hadn't been cancelled there
// would've been an exception thrown as replacing views isn't allowed.
- assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(syncView)
- assertThat(windowDecorViewHost.viewHost!!.view!!.layoutParams.width)
- .isEqualTo(syncAttrs.width)
+ assertThat(windowDecorViewHost.view()).isEqualTo(syncView)
+ assertThat(windowDecorViewHost.view()!!.layoutParams.width).isEqualTo(syncAttrs.width)
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -160,11 +111,11 @@
configuration = context.resources.configuration,
)
- assertThat(windowDecorViewHost.viewHost).isNull()
+ assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isFalse()
advanceUntilIdle()
- assertThat(windowDecorViewHost.viewHost).isNotNull()
+ assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isTrue()
}
@OptIn(ExperimentalCoroutinesApi::class)
@@ -187,9 +138,8 @@
advanceUntilIdle()
- assertThat(windowDecorViewHost.viewHost).isNotNull()
- assertThat(windowDecorViewHost.viewHost!!.view).isNotNull()
- assertThat(windowDecorViewHost.viewHost!!.view).isEqualTo(otherView)
+ assertThat(windowDecorViewHost.viewHostAdapter.isInitialized()).isTrue()
+ assertThat(windowDecorViewHost.view()).isEqualTo(otherView)
}
@Test
@@ -207,16 +157,15 @@
val t = mock(SurfaceControl.Transaction::class.java)
windowDecorViewHost.release(t)
- verify(windowDecorViewHost.viewHost!!).release()
- verify(t).remove(windowDecorViewHost.surfaceControl)
+ verify(windowDecorViewHost.viewHostAdapter).release(t)
}
private fun CoroutineScope.createDefaultViewHost() = DefaultWindowDecorViewHost(
context = context,
mainScope = this,
display = context.display,
- surfaceControlViewHostFactory = { c, d, wwm, s ->
- spy(SurfaceControlViewHost(c, d, wwm, s))
- }
+ viewHostAdapter = spy(SurfaceControlViewHostAdapter(context, context.display)),
)
+
+ private fun DefaultWindowDecorViewHost.view(): View? = viewHostAdapter.viewHost?.view
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplierTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplierTest.kt
new file mode 100644
index 0000000..a7e4213
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/PooledWindowDecorViewHostSupplierTest.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.testing.AndroidTestingRunner
+import android.view.SurfaceControl
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.sysui.ShellInit
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/**
+ * Tests for [PooledWindowDecorViewHostSupplier].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:PooledWindowDecorViewHostSupplierTest
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class PooledWindowDecorViewHostSupplierTest : ShellTestCase() {
+
+ private val testExecutor = TestShellExecutor()
+ private val testShellInit = ShellInit(testExecutor)
+ @Mock
+ private lateinit var mockViewHostFactory: ReusableWindowDecorViewHost.Factory
+
+ private lateinit var supplier: PooledWindowDecorViewHostSupplier
+
+ @Test
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun onInit_warmsAndPoolsViewHosts() = runTest {
+ supplier = createSupplier(maxPoolSize = 5, preWarmSize = 2)
+ val mockViewHost1 = mock<ReusableWindowDecorViewHost>()
+ val mockViewHost2 = mock<ReusableWindowDecorViewHost>()
+ whenever(mockViewHostFactory
+ .create(context, this, context.display, id = 0))
+ .thenReturn(mockViewHost1)
+ whenever(mockViewHostFactory
+ .create(context, this, context.display, id = 1))
+ .thenReturn(mockViewHost2)
+
+ testExecutor.flushAll()
+ advanceUntilIdle()
+
+ // Both were warmed up.
+ verify(mockViewHost1).warmUp()
+ verify(mockViewHost2).warmUp()
+ // Both were released, so re-acquiring them provides the same instance.
+ assertThat(mockViewHost2)
+ .isEqualTo(supplier.acquire(context, context.display))
+ assertThat(mockViewHost1)
+ .isEqualTo(supplier.acquire(context, context.display))
+ }
+
+ @Test(expected = Throwable::class)
+ fun onInit_warmUpSizeExceedsPoolSize_throws() = runTest {
+ createSupplier(maxPoolSize = 3, preWarmSize = 4)
+ }
+
+ @Test
+ fun acquire_poolHasInstances_reuses() = runTest {
+ supplier = createSupplier(maxPoolSize = 5, preWarmSize = 0)
+
+ // Prepare the pool with one instance.
+ val mockViewHost = mock<ReusableWindowDecorViewHost>()
+ supplier.release(mockViewHost, SurfaceControl.Transaction())
+
+ assertThat(mockViewHost)
+ .isEqualTo(supplier.acquire(context, context.display))
+ verify(mockViewHostFactory, never()).create(any(), any(), any(), any())
+ }
+
+ @Test
+ fun acquire_pooledHasZeroInstances_creates() = runTest {
+ supplier = createSupplier(maxPoolSize = 5, preWarmSize = 0)
+
+ supplier.acquire(context, context.display)
+
+ verify(mockViewHostFactory).create(context, this, context.display, id = 0)
+ }
+
+ @Test
+ fun release_poolBelowLimit_caches() = runTest {
+ supplier = createSupplier(maxPoolSize = 5, preWarmSize = 0)
+
+ val mockViewHost = mock<ReusableWindowDecorViewHost>()
+ val mockT = mock<SurfaceControl.Transaction>()
+ supplier.release(mockViewHost, mockT)
+
+ assertThat(mockViewHost)
+ .isEqualTo(supplier.acquire(context, context.display))
+ }
+
+ @Test
+ fun release_poolBelowLimit_doesNotReleaseViewHost() = runTest {
+ supplier = createSupplier(maxPoolSize = 5, preWarmSize = 0)
+
+ val mockViewHost = mock<ReusableWindowDecorViewHost>()
+ val mockT = mock<SurfaceControl.Transaction>()
+ supplier.release(mockViewHost, mockT)
+
+ verify(mockViewHost, never()).release(mockT)
+ }
+
+ @Test
+ fun release_poolAtLimit_doesNotCache() = runTest {
+ supplier = createSupplier(maxPoolSize = 1, preWarmSize = 0)
+ val mockT = mock<SurfaceControl.Transaction>()
+ val mockViewHost = mock<ReusableWindowDecorViewHost>()
+ supplier.release(mockViewHost, mockT) // Maxes pool.
+
+ val mockViewHost2 = mock<ReusableWindowDecorViewHost>()
+ supplier.release(mockViewHost2, mockT) // Beyond limit.
+
+ assertThat(mockViewHost)
+ .isEqualTo(supplier.acquire(context, context.display))
+ // Second one wasn't cached, so the acquired one should've been a new instance.
+ assertThat(mockViewHost2)
+ .isNotEqualTo(supplier.acquire(context, context.display))
+ }
+
+ @Test
+ fun release_poolAtLimit_releasesViewHost() = runTest {
+ supplier = createSupplier(maxPoolSize = 1, preWarmSize = 0)
+ val mockT = mock<SurfaceControl.Transaction>()
+ val mockViewHost = mock<ReusableWindowDecorViewHost>()
+ supplier.release(mockViewHost, mockT) // Maxes pool.
+
+ val mockViewHost2 = mock<ReusableWindowDecorViewHost>()
+ supplier.release(mockViewHost2, mockT) // Beyond limit.
+
+ // Second one doesn't fit, so it needs to be released.
+ verify(mockViewHost2).release(mockT)
+ }
+
+ private fun CoroutineScope.createSupplier(
+ maxPoolSize: Int,
+ preWarmSize: Int
+ ) = PooledWindowDecorViewHostSupplier(
+ context,
+ this,
+ testShellInit,
+ mockViewHostFactory,
+ maxPoolSize,
+ preWarmSize
+ ).also {
+ testShellInit.init()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHostTest.kt
new file mode 100644
index 0000000..de2444e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/ReusableWindowDecorViewHostTest.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.SurfaceControl
+import android.view.View
+import android.view.WindowManager
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+
+/**
+ * Tests for [ReusableWindowDecorViewHost].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:ReusableWindowDecorViewHostTest
+ */
+@SmallTest
[email protected]
+@RunWith(AndroidTestingRunner::class)
+class ReusableWindowDecorViewHostTest : ShellTestCase() {
+
+ @Test
+ fun warmUp_addsRootView() = runTest {
+ val reusableVH = createReusableViewHost().apply {
+ warmUp()
+ }
+
+ assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
+ assertThat(reusableVH.view()).isEqualTo(reusableVH.rootView)
+ }
+
+ @Test
+ fun update_differentView_replacesView() = runTest {
+ val view = View(context)
+ val lp = WindowManager.LayoutParams()
+ val reusableVH = createReusableViewHost()
+ reusableVH.updateView(view, lp, context.resources.configuration, null)
+
+ assertThat(reusableVH.rootView.childCount).isEqualTo(1)
+ assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(view)
+
+ val newView = View(context)
+ val newLp = WindowManager.LayoutParams()
+ reusableVH.updateView(newView, newLp, context.resources.configuration, null)
+
+ assertThat(reusableVH.rootView.childCount).isEqualTo(1)
+ assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(newView)
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun updateView_clearsPendingAsyncJob() = runTest {
+ val reusableVH = createReusableViewHost()
+ val asyncView = View(context)
+ val syncView = View(context)
+ val asyncAttrs = WindowManager.LayoutParams(100, 100)
+ val syncAttrs = WindowManager.LayoutParams(200, 200)
+
+ reusableVH.updateViewAsync(
+ view = asyncView,
+ attrs = asyncAttrs,
+ configuration = context.resources.configuration,
+ )
+
+ // No view host yet, since the coroutine hasn't run.
+ assertThat(reusableVH.viewHostAdapter.isInitialized()).isFalse()
+
+ reusableVH.updateView(
+ view = syncView,
+ attrs = syncAttrs,
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ // Would run coroutine if it hadn't been cancelled.
+ advanceUntilIdle()
+
+ assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
+ // View host view/attrs should match the ones from the sync call, plus, since the
+ // sync/async were made with different views, if the job hadn't been cancelled there
+ // would've been an exception thrown as replacing views isn't allowed.
+ assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(syncView)
+ assertThat(reusableVH.view()!!.layoutParams.width).isEqualTo(syncAttrs.width)
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun updateViewAsync() = runTest {
+ val reusableVH = createReusableViewHost()
+ val view = View(context)
+ val attrs = WindowManager.LayoutParams(100, 100)
+
+ reusableVH.updateViewAsync(
+ view = view,
+ attrs = attrs,
+ configuration = context.resources.configuration,
+ )
+
+ assertThat(reusableVH.viewHostAdapter.isInitialized()).isFalse()
+
+ advanceUntilIdle()
+
+ assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun updateViewAsync_clearsPendingAsyncJob() = runTest {
+ val reusableVH = createReusableViewHost()
+
+ val view = View(context)
+ reusableVH.updateViewAsync(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ )
+ val otherView = View(context)
+ reusableVH.updateViewAsync(
+ view = otherView,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ )
+
+ advanceUntilIdle()
+
+ assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue()
+ assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(otherView)
+ }
+
+ @Test
+ fun release() = runTest {
+ val reusableVH = createReusableViewHost()
+
+ val view = View(context)
+ reusableVH.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100),
+ configuration = context.resources.configuration,
+ onDrawTransaction = null
+ )
+
+ val t = mock(SurfaceControl.Transaction::class.java)
+ reusableVH.release(t)
+
+ verify(reusableVH.viewHostAdapter).release(t)
+ }
+
+ private fun CoroutineScope.createReusableViewHost() = ReusableWindowDecorViewHost(
+ context = context,
+ mainScope = this,
+ display = context.display,
+ id = 1,
+ viewHostAdapter = spy(SurfaceControlViewHostAdapter(context, context.display)),
+ )
+
+ private fun ReusableWindowDecorViewHost.view(): View? = viewHostAdapter.viewHost?.view
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapterTest.kt
new file mode 100644
index 0000000..d6c80a7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/viewhost/SurfaceControlViewHostAdapterTest.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor.viewhost
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.View
+import android.view.WindowManager
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+
+/**
+ * Tests for [SurfaceControlViewHostAdapter].
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:SurfaceControlViewHostAdapterTest
+ */
+@SmallTest
[email protected]
+@RunWith(AndroidTestingRunner::class)
+class SurfaceControlViewHostAdapterTest : ShellTestCase() {
+
+ private lateinit var adapter: SurfaceControlViewHostAdapter
+
+ @Before
+ fun setUp() {
+ adapter = SurfaceControlViewHostAdapter(
+ context,
+ context.display,
+ surfaceControlViewHostFactory = { c, d, wwm, s ->
+ spy(SurfaceControlViewHost(c, d, wwm, s))
+ }
+ )
+ }
+
+ @Test
+ fun prepareViewHost() {
+ adapter.prepareViewHost(context.resources.configuration)
+
+ assertThat(adapter.viewHost).isNotNull()
+ }
+
+ @Test
+ fun prepareViewHost_alreadyCreated_skips() {
+ adapter.prepareViewHost(context.resources.configuration)
+
+ val viewHost = adapter.viewHost!!
+
+ adapter.prepareViewHost(context.resources.configuration)
+
+ assertThat(adapter.viewHost).isEqualTo(viewHost)
+ }
+
+ @Test
+ fun updateView_layoutInViewHost() {
+ val view = View(context)
+ adapter.prepareViewHost(context.resources.configuration)
+
+ adapter.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100)
+ )
+
+ assertThat(adapter.isInitialized()).isTrue()
+ assertThat(adapter.view()).isEqualTo(view)
+ }
+
+ @Test
+ fun updateView_alreadyLaidOut_relayouts() {
+ val view = View(context)
+ adapter.prepareViewHost(context.resources.configuration)
+ adapter.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100)
+ )
+
+ val otherParams = WindowManager.LayoutParams(200, 200)
+ adapter.updateView(
+ view = view,
+ attrs = otherParams
+ )
+
+ assertThat(adapter.view()).isEqualTo(view)
+ assertThat(adapter.view()!!.layoutParams.width).isEqualTo(otherParams.width)
+ }
+
+ @Test
+ fun updateView_replacingView_throws() {
+ val view = View(context)
+ adapter.prepareViewHost(context.resources.configuration)
+ adapter.updateView(
+ view = view,
+ attrs = WindowManager.LayoutParams(100, 100)
+ )
+
+ val otherView = View(context)
+ assertThrows(Exception::class.java) {
+ adapter.updateView(
+ view = otherView,
+ attrs = WindowManager.LayoutParams(100, 100)
+ )
+ }
+ }
+
+ @Test
+ fun release() {
+ adapter.prepareViewHost(context.resources.configuration)
+ adapter.updateView(
+ view = View(context),
+ attrs = WindowManager.LayoutParams(100, 100)
+ )
+
+ val mockT = mock(SurfaceControl.Transaction::class.java)
+ adapter.release(mockT)
+
+ verify(adapter.viewHost!!).release()
+ verify(mockT).remove(adapter.rootSurface)
+ }
+
+ private fun SurfaceControlViewHostAdapter.view(): View? = viewHost?.view
+}
diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig
index faea6d4..ab052b9 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -121,3 +121,11 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "iso_gainmap_apis"
+ is_exported: true
+ namespace: "core_graphics"
+ description: "APIs that expose gainmap metadata corresponding to those defined in ISO 21496-1"
+ bug: "349357636"
+}
diff --git a/libs/hwui/apex/android_bitmap.cpp b/libs/hwui/apex/android_bitmap.cpp
index c80a9b4..000f109 100644
--- a/libs/hwui/apex/android_bitmap.cpp
+++ b/libs/hwui/apex/android_bitmap.cpp
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-#include <log/log.h>
-
-#include "android/graphics/bitmap.h"
-#include "TypeCast.h"
-#include "GraphicsJNI.h"
-
+#include <Gainmap.h>
#include <GraphicsJNI.h>
-#include <hwui/Bitmap.h>
#include <SkBitmap.h>
#include <SkColorSpace.h>
#include <SkImageInfo.h>
#include <SkRefCnt.h>
#include <SkStream.h>
+#include <hwui/Bitmap.h>
+#include <log/log.h>
#include <utils/Color.h>
+#include "GraphicsJNI.h"
+#include "TypeCast.h"
+#include "android/graphics/bitmap.h"
+
using namespace android;
ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj) {
@@ -215,6 +215,14 @@
int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
AndroidBitmapCompressFormat inFormat, int32_t quality, void* userContext,
AndroidBitmap_CompressWriteFunc fn) {
+ return ABitmap_compressWithGainmap(info, dataSpace, pixels, nullptr, -1.f, inFormat, quality,
+ userContext, fn);
+}
+
+int ABitmap_compressWithGainmap(const AndroidBitmapInfo* info, ADataSpace dataSpace,
+ const void* pixels, const void* gainmapPixels, float hdrSdrRatio,
+ AndroidBitmapCompressFormat inFormat, int32_t quality,
+ void* userContext, AndroidBitmap_CompressWriteFunc fn) {
Bitmap::JavaCompressFormat format;
switch (inFormat) {
case ANDROID_BITMAP_COMPRESS_FORMAT_JPEG:
@@ -275,7 +283,7 @@
// besides ADATASPACE_UNKNOWN as an error?
cs = nullptr;
} else {
- cs = uirenderer::DataSpaceToColorSpace((android_dataspace) dataSpace);
+ cs = uirenderer::DataSpaceToColorSpace((android_dataspace)dataSpace);
// DataSpaceToColorSpace treats UNKNOWN as SRGB, but compress forces the
// client to specify SRGB if that is what they want.
if (!cs || dataSpace == ADATASPACE_UNKNOWN) {
@@ -292,16 +300,70 @@
auto imageInfo =
SkImageInfo::Make(info->width, info->height, colorType, alphaType, std::move(cs));
- SkBitmap bitmap;
- // We are not going to modify the pixels, but installPixels expects them to
- // not be const, since for all it knows we might want to draw to the SkBitmap.
- if (!bitmap.installPixels(imageInfo, const_cast<void*>(pixels), info->stride)) {
- return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+
+ // Validate the image info
+ {
+ SkBitmap tempBitmap;
+ if (!tempBitmap.installPixels(imageInfo, const_cast<void*>(pixels), info->stride)) {
+ return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+ }
+ }
+
+ SkPixelRef pixelRef =
+ SkPixelRef(info->width, info->height, const_cast<void*>(pixels), info->stride);
+
+ auto bitmap = Bitmap::createFrom(imageInfo, pixelRef);
+
+ if (gainmapPixels) {
+ auto gainmap = sp<uirenderer::Gainmap>::make();
+ gainmap->info.fGainmapRatioMin = {
+ 1.f,
+ 1.f,
+ 1.f,
+ 1.f,
+ };
+ gainmap->info.fGainmapRatioMax = {
+ hdrSdrRatio,
+ hdrSdrRatio,
+ hdrSdrRatio,
+ 1.f,
+ };
+ gainmap->info.fGainmapGamma = {
+ 1.f,
+ 1.f,
+ 1.f,
+ 1.f,
+ };
+
+ static constexpr auto kDefaultEpsilon = 1.f / 64.f;
+ gainmap->info.fEpsilonSdr = {
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ 1.f,
+ };
+ gainmap->info.fEpsilonHdr = {
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ 1.f,
+ };
+ gainmap->info.fDisplayRatioSdr = 1.f;
+ gainmap->info.fDisplayRatioHdr = hdrSdrRatio;
+
+ SkPixelRef gainmapPixelRef = SkPixelRef(info->width, info->height,
+ const_cast<void*>(gainmapPixels), info->stride);
+ auto gainmapBitmap = Bitmap::createFrom(imageInfo, gainmapPixelRef);
+ gainmap->bitmap = std::move(gainmapBitmap);
+ bitmap->setGainmap(std::move(gainmap));
}
CompressWriter stream(userContext, fn);
- return Bitmap::compress(bitmap, format, quality, &stream) ? ANDROID_BITMAP_RESULT_SUCCESS
- : ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
+
+ return bitmap->compress(format, quality, &stream)
+
+ ? ANDROID_BITMAP_RESULT_SUCCESS
+ : ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
AHardwareBuffer* ABitmap_getHardwareBuffer(ABitmap* bitmapHandle) {
diff --git a/libs/hwui/apex/include/android/graphics/bitmap.h b/libs/hwui/apex/include/android/graphics/bitmap.h
index 8c4b439..6f65e9e 100644
--- a/libs/hwui/apex/include/android/graphics/bitmap.h
+++ b/libs/hwui/apex/include/android/graphics/bitmap.h
@@ -65,6 +65,13 @@
ANDROID_API int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
AndroidBitmapCompressFormat format, int32_t quality, void* userContext,
AndroidBitmap_CompressWriteFunc);
+// If gainmapPixels is null, then no gainmap is encoded, and hdrSdrRatio is
+// unused
+ANDROID_API int ABitmap_compressWithGainmap(const AndroidBitmapInfo* info, ADataSpace dataSpace,
+ const void* pixels, const void* gainmapPixels,
+ float hdrSdrRatio, AndroidBitmapCompressFormat format,
+ int32_t quality, void* userContext,
+ AndroidBitmap_CompressWriteFunc);
/**
* Retrieve the native object associated with a HARDWARE Bitmap.
*
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
index 0fffee7..71972d0 100644
--- a/libs/hwui/jni/Gainmap.cpp
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -16,6 +16,9 @@
#include <Gainmap.h>
+#include "SkColorType.h"
+#include "SkGainmapInfo.h"
+
#ifdef __ANDROID__
#include <binder/Parcel.h>
#endif
@@ -36,6 +39,28 @@
return reinterpret_cast<Gainmap*>(gainmap);
}
+static SkGainmapInfo::BaseImageType baseImageTypeFromJava(jint direction) {
+ switch (direction) {
+ case 0:
+ return SkGainmapInfo::BaseImageType::kSDR;
+ case 1:
+ return SkGainmapInfo::BaseImageType::kHDR;
+ default:
+ LOG_ALWAYS_FATAL("Unrecognized Gainmap direction: %d", direction);
+ }
+}
+
+static jint baseImageTypeToJava(SkGainmapInfo::BaseImageType type) {
+ switch (type) {
+ case SkGainmapInfo::BaseImageType::kSDR:
+ return 0;
+ case SkGainmapInfo::BaseImageType::kHDR:
+ return 1;
+ default:
+ LOG_ALWAYS_FATAL("Unrecognized base image: %d", type);
+ }
+}
+
static int getCreateFlags(const sk_sp<Bitmap>& bitmap) {
int flags = 0;
if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
@@ -169,6 +194,36 @@
return fromJava(gainmapPtr)->info.fDisplayRatioSdr;
}
+static void Gainmap_setAlternativeColorSpace(JNIEnv*, jobject, jlong gainmapPtr,
+ jlong colorSpacePtr) {
+ auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
+ fromJava(gainmapPtr)->info.fGainmapMathColorSpace = colorSpace;
+}
+
+static jobject Gainmap_getAlternativeColorSpace(JNIEnv* env, jobject, jlong gainmapPtr) {
+ const auto javaGainmap = fromJava(gainmapPtr);
+ auto colorSpace = javaGainmap->info.fGainmapMathColorSpace.get();
+ if (colorSpace == nullptr) {
+ return nullptr;
+ }
+
+ auto colorType = javaGainmap->bitmap->colorType();
+ // A8 bitmaps don't support colorspaces, but an alternative colorspace is
+ // still valid for configuring the gainmap math, so use RGBA8888 instead.
+ if (colorType == kAlpha_8_SkColorType) {
+ colorType = kRGBA_8888_SkColorType;
+ }
+ return GraphicsJNI::getColorSpace(env, colorSpace, colorType);
+}
+
+static void Gainmap_setDirection(JNIEnv*, jobject, jlong gainmapPtr, jint direction) {
+ fromJava(gainmapPtr)->info.fBaseImageType = baseImageTypeFromJava(direction);
+}
+
+static jint Gainmap_getDirection(JNIEnv* env, jobject, jlong gainmapPtr) {
+ return baseImageTypeToJava(fromJava(gainmapPtr)->info.fBaseImageType);
+}
+
// ----------------------------------------------------------------------------
// Serialization
// ----------------------------------------------------------------------------
@@ -260,6 +315,11 @@
{"nGetDisplayRatioHdr", "(J)F", (void*)Gainmap_getDisplayRatioHdr},
{"nSetDisplayRatioSdr", "(JF)V", (void*)Gainmap_setDisplayRatioSdr},
{"nGetDisplayRatioSdr", "(J)F", (void*)Gainmap_getDisplayRatioSdr},
+ {"nSetAlternativeColorSpace", "(JJ)V", (void*)Gainmap_setAlternativeColorSpace},
+ {"nGetAlternativeColorSpace", "(J)Landroid/graphics/ColorSpace;",
+ (void*)Gainmap_getAlternativeColorSpace},
+ {"nSetDirection", "(JI)V", (void*)Gainmap_setDirection},
+ {"nGetDirection", "(J)I", (void*)Gainmap_getDirection},
{"nWriteGainmapToParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_writeToParcel},
{"nReadGainmapFromParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_readFromParcel},
};
diff --git a/libs/hwui/libhwui.map.txt b/libs/hwui/libhwui.map.txt
index d03ceb4..2414299 100644
--- a/libs/hwui/libhwui.map.txt
+++ b/libs/hwui/libhwui.map.txt
@@ -13,6 +13,7 @@
ABitmapConfig_getFormatFromConfig;
ABitmapConfig_getConfigFromFormat;
ABitmap_compress;
+ ABitmap_compressWithGainmap;
ABitmap_getHardwareBuffer;
ACanvas_isSupportedPixelFormat;
ACanvas_getNativeHandleFromJava;
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 6ac9695..e52e0b1 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -30,24 +30,14 @@
"file_patterns": ["(?i)drm|crypto"]
},
{
- "name": "CtsMediaDrmFrameworkTestCases",
- "options" : [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ],
+ "name": "CtsMediaDrmFrameworkTestCases_Presubmit",
"file_patterns": ["(?i)drm|crypto"]
},
{
"file_patterns": [
"[^/]*(LoudnessCodec)[^/]*\\.java"
],
- "name": "LoudnessCodecApiTest",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ]
+ "name": "LoudnessCodecApiTest_Presubmit"
}
]
}
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 1a3d7b7..0efefb9 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -519,7 +519,7 @@
int[] counts = new int[countSet.size()];
int index = 0;
for (int count : countSet) {
- counts[index++] = count;
+ counts[index++] = count;
}
return counts;
}
@@ -595,21 +595,22 @@
}
/** @hide */
- public static int convertDeviceTypeToInternalDevice(int deviceType) {
+ public static int convertDeviceTypeToInternalDevice(@AudioDeviceType int deviceType) {
return EXT_TO_INT_DEVICE_MAPPING.get(deviceType, AudioSystem.DEVICE_NONE);
}
/** @hide */
- public static int convertInternalDeviceToDeviceType(int intDevice) {
+ public static @AudioDeviceType int convertInternalDeviceToDeviceType(int intDevice) {
return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN);
}
/** @hide */
- public static int convertDeviceTypeToInternalInputDevice(int deviceType) {
+ public static int convertDeviceTypeToInternalInputDevice(@AudioDeviceType int deviceType) {
return convertDeviceTypeToInternalInputDevice(deviceType, "");
}
/** @hide */
- public static int convertDeviceTypeToInternalInputDevice(int deviceType, String address) {
+ public static int convertDeviceTypeToInternalInputDevice(@AudioDeviceType int deviceType,
+ String address) {
int internalType = EXT_TO_INT_INPUT_DEVICE_MAPPING.get(deviceType, AudioSystem.DEVICE_NONE);
if (internalType == AudioSystem.DEVICE_IN_BUILTIN_MIC
&& "back".equals(address)) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 4981cb3..e2e7a46 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -56,6 +56,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioAttributes.AttributeSystemUsage;
+import android.media.AudioDeviceInfo;
import android.media.CallbackUtil.ListenerInfo;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
@@ -8157,7 +8158,7 @@
* @hide
*/
public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
- int deviceType = deviceInfo.getType();
+ @AudioDeviceInfo.AudioDeviceType int deviceType = deviceInfo.getType();
int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
|| deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
: deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index f33a744..7b9ff23 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -26,6 +26,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.Trace;
import android.util.AndroidRuntimeException;
import android.util.Log;
@@ -314,8 +315,13 @@
public final int play(int soundID, float leftVolume, float rightVolume,
int priority, int loop, float rate) {
// FIXME: b/174876164 implement device id for soundpool
- baseStart(0);
- return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId());
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_AUDIO, "SoundPool.play");
+ baseStart(0);
+ return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId());
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_AUDIO);
+ }
}
/**
diff --git a/media/java/android/media/projection/TEST_MAPPING b/media/java/android/media/projection/TEST_MAPPING
index 7aa9118..b33097c 100644
--- a/media/java/android/media/projection/TEST_MAPPING
+++ b/media/java/android/media/projection/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "MediaProjectionTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "MediaProjectionTests"
}
]
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 25b6bfa..b673e03 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -4253,8 +4253,8 @@
* AudioFormat.CHANNEL_OUT_DEFAULT.
* @param format desired format. Use default when it's AudioFormat.ENCODING_DEFAULT.
*/
- public void overrideAudioSink(int audioType, String audioAddress, int samplingRate,
- int channelMask, int format) {
+ public void overrideAudioSink(@AudioDeviceInfo.AudioDeviceType int audioType,
+ String audioAddress, int samplingRate, int channelMask, int format) {
try {
mInterface.overrideAudioSink(audioType, audioAddress, samplingRate, channelMask,
format);
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 9f32a83..4c0b8d0 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -21,6 +21,9 @@
#include <algorithm>
#include <thread>
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+
#include "SoundPool.h"
namespace android
@@ -135,8 +138,10 @@
return 0;
}
+ ATRACE_BEGIN("SoundPool::play (native)");
const int32_t streamID = mStreamManager.queueForPlay(
sound, soundID, leftVolume, rightVolume, priority, loop, rate, playerIId);
+ ATRACE_END();
ALOGV("%s returned %d", __func__, streamID);
return streamID;
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index 5cf807d..17cdee4 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -132,6 +132,7 @@
# Optional additions that should not override any previous mapping.
?application/x-wifi-config ?xml
+?multipart/related mht
# Special cases where Android has a strong opinion about mappings, so we
# define them very last and make them override in both directions (no "?").
diff --git a/native/android/TEST_MAPPING b/native/android/TEST_MAPPING
index 7c71098..be84574 100644
--- a/native/android/TEST_MAPPING
+++ b/native/android/TEST_MAPPING
@@ -14,12 +14,7 @@
"file_patterns": ["permission_manager.cpp"]
},
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-filter": "android.os.cts.PerformanceHintManagerTest"
- }
- ],
+ "name": "CtsOsTestCases_cts_performancehintmanagertest",
"file_patterns": ["performance_hint.cpp"]
}
],
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 25c063d6..202535d 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -273,6 +273,7 @@
ASurfaceTransaction_fromJava; # introduced=34
ASurfaceTransaction_reparent; # introduced=29
ASurfaceTransaction_setBuffer; # introduced=29
+ ASurfaceTransaction_setBufferWithRelease; # introduced=36
ASurfaceTransaction_setBufferAlpha; # introduced=29
ASurfaceTransaction_setBufferDataSpace; # introduced=29
ASurfaceTransaction_setBufferTransparency; # introduced=29
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 6ce83cd..e46db6b 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -416,6 +416,35 @@
transaction->setBuffer(surfaceControl, graphic_buffer, fence);
}
+void ASurfaceTransaction_setBufferWithRelease(
+ ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ AHardwareBuffer* buffer, int acquire_fence_fd, void* _Null_unspecified context,
+ ASurfaceTransaction_OnBufferRelease aReleaseCallback) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+ CHECK_NOT_NULL(aReleaseCallback);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ sp<GraphicBuffer> graphic_buffer(GraphicBuffer::fromAHardwareBuffer(buffer));
+
+ std::optional<sp<Fence>> fence = std::nullopt;
+ if (acquire_fence_fd != -1) {
+ fence = new Fence(acquire_fence_fd);
+ }
+
+ ReleaseBufferCallback releaseBufferCallback =
+ [context,
+ aReleaseCallback](const ReleaseCallbackId&, const sp<Fence>& releaseFence,
+ std::optional<uint32_t> /* currentMaxAcquiredBufferCount */) {
+ (*aReleaseCallback)(context, (releaseFence) ? releaseFence->dup() : -1);
+ };
+
+ transaction->setBuffer(surfaceControl, graphic_buffer, fence, /* frameNumber */ std::nullopt,
+ /* producerId */ 0, releaseBufferCallback);
+}
+
void ASurfaceTransaction_setGeometry(ASurfaceTransaction* aSurfaceTransaction,
ASurfaceControl* aSurfaceControl, const ARect& source,
const ARect& destination, int32_t transform) {
diff --git a/native/webview/TEST_MAPPING b/native/webview/TEST_MAPPING
index 07f4383..3858059 100644
--- a/native/webview/TEST_MAPPING
+++ b/native/webview/TEST_MAPPING
@@ -1,28 +1,13 @@
{
"presubmit": [
{
- "name": "CtsWebkitTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsWebkitTestCases"
},
{
- "name": "CtsSdkSandboxWebkitTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSdkSandboxWebkitTestCases"
},
{
- "name": "CtsHostsideWebViewTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsHostsideWebViewTests"
},
{
"name": "GtsWebViewTestCases",
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 5b6b6c0..e7cb76c 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -205,6 +205,7 @@
method public int getSelectionModeForCategory(String);
method public boolean isDefaultServiceForAid(android.content.ComponentName, String);
method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
+ method @FlaggedApi("android.nfc.enable_card_emulation_euicc") public boolean isEuiccSupported();
method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index cc5ff81..bc8a7af 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -98,7 +98,6 @@
public final class CardEmulation {
method @FlaggedApi("android.permission.flags.wallet_role_enabled") @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static android.content.ComponentName getPreferredPaymentService(@NonNull android.content.Context);
method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
- method @FlaggedApi("android.nfc.enable_card_emulation_euicc") public boolean isEuiccSupported();
method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void recoverRoutingTable(@NonNull android.app.Activity);
}
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index a72a896..83ad32c 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -992,9 +992,7 @@
* Is EUICC supported as a Secure Element EE which supports off host card emulation.
*
* @return true if the device supports EUICC for off host card emulation, false otherwise.
- * @hide
*/
- @SystemApi
@FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
public boolean isEuiccSupported() {
return callServiceReturn(() -> sService.isEuiccSupported(), false);
diff --git a/packages/CarrierDefaultApp/res/values-ar/strings.xml b/packages/CarrierDefaultApp/res/values-ar/strings.xml
index fe746f2..53a2733 100644
--- a/packages/CarrierDefaultApp/res/values-ar/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ar/strings.xml
@@ -8,7 +8,7 @@
<string name="portal_notification_detail" msgid="2295729385924660881">"النقر للانتقال إلى موقع %s الإلكتروني"</string>
<string name="no_data_notification_detail" msgid="3112125343857014825">"يُرجى الاتصال بمقدم الخدمة %s"</string>
<string name="no_mobile_data_connection_title" msgid="7449525772416200578">"لا يوجد اتصال بيانات الجوال"</string>
- <string name="no_mobile_data_connection" msgid="544980465184147010">"إضافة بيانات أو خطة تجوال خلال %s"</string>
+ <string name="no_mobile_data_connection" msgid="544980465184147010">"إضافة بيانات أو خطة تجوال خلال %%s"</string>
<string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"حالة بيانات الجوّال"</string>
<string name="action_bar_label" msgid="4290345990334377177">"تسجيل الدخول إلى شبكة الجوّال"</string>
<string name="ssl_error_warning" msgid="3127935140338254180">"الشبكة التي تحاول الانضمام إليها بها مشاكل أمنية."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ur/strings.xml b/packages/CarrierDefaultApp/res/values-ur/strings.xml
index d6225c2..20d1300 100644
--- a/packages/CarrierDefaultApp/res/values-ur/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ur/strings.xml
@@ -16,7 +16,7 @@
<string name="ssl_error_continue" msgid="1138548463994095584">"براؤزر کے ذریعے بہرحال جاری رکھیں"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"پرفارمینس بوسٹ"</string>
<string name="performance_boost_notification_title" msgid="3126203390685781861">"آپ کے کیریئر سے 5G کے اختیارات"</string>
- <string name="performance_boost_notification_detail" msgid="216569851036236346">"اپنی ایپ کے تجربے کے اختیارات دیکھنے کے لیے %s کی ویب سائٹ ملاحظہ کریں"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"اپنی ایپ کے تجربے کے اختیارات دیکھنے کے لیے %%s کی ویب سائٹ ملاحظہ کریں"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ابھی نہیں"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"نظم کریں"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"پرفارمینس بوسٹ خریدیں۔"</string>
diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml
index 3b98438..77c0d41 100644
--- a/packages/CredentialManager/res/values-te/strings.xml
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -52,7 +52,7 @@
<string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"మరొక పరికరంలో పాస్-కీని క్రియేట్ చేయాలా?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"మరొక పరికరంలో పాస్వర్డ్ను సేవ్ చేయాలా?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"మరో పరికరంలో సైన్-ఇన్ని సేవ్ చేయాలా?"</string>
- <string name="use_provider_for_all_title" msgid="4201020195058980757">"మీ అన్ని సైన్-ఇన్ వివరాల కోసం <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ను ఉపయోగించాలా?"</string>
+ <string name="use_provider_for_all_title" msgid="4201020195058980757">"మీరు సైన్-ఇన్ చేసే సందర్భాలన్నిటికీ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ను ఉపయోగించాలా?"</string>
<string name="use_provider_for_all_description" msgid="1998772715863958997">"<xliff:g id="USERNAME">%1$s</xliff:g> కోసం ఈ పాస్వర్డ్ మేనేజర్ మీకు సులభంగా సైన్ ఇన్ చేయడంలో సహాయపడటానికి మీ పాస్వర్డ్లు, పాస్-కీలను స్టోర్ చేస్తుంది"</string>
<string name="set_as_default" msgid="4415328591568654603">"ఆటోమేటిక్ సెట్టింగ్గా సెట్ చేయండి"</string>
<string name="settings" msgid="6536394145760913145">"సెట్టింగ్లు"</string>
diff --git a/packages/PrintSpooler/TEST_MAPPING b/packages/PrintSpooler/TEST_MAPPING
index ad3b44f..f8bf8a0 100644
--- a/packages/PrintSpooler/TEST_MAPPING
+++ b/packages/PrintSpooler/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPrintTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ]
+ "name": "CtsPrintTestCases_Presubmit"
}
],
"postsubmit": [
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index b997c35..0cb85d8 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -42,8 +42,6 @@
"SettingsLibIllustrationPreference",
"SettingsLibLayoutPreference",
"SettingsLibMainSwitchPreference",
- "SettingsLibMetadata",
- "SettingsLibPreference",
"SettingsLibProfileSelector",
"SettingsLibProgressBar",
"SettingsLibRestrictedLockUtils",
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
index 9be0e71..5fcf478 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceBinding.kt
@@ -108,6 +108,9 @@
/** Abstract preference screen to provide preference hierarchy and binding factory. */
interface PreferenceScreenCreator : PreferenceScreenMetadata, PreferenceScreenProvider {
+ /** Returns if the flag (e.g. for rollout) is enabled on current screen. */
+ fun isFlagEnabled(context: Context): Boolean = true
+
val preferenceBindingFactory: PreferenceBindingFactory
get() = DefaultPreferenceBindingFactory
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
index 68f640b..a270681 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceFragment.kt
@@ -44,13 +44,8 @@
fun createPreferenceScreenFromResource() =
factory.inflate(getPreferenceScreenResId(context))
- if (!usePreferenceScreenMetadata()) return createPreferenceScreenFromResource()
-
- val screenKey = getPreferenceScreenBindingKey(context)
val screenCreator =
- (PreferenceScreenRegistry[screenKey] as? PreferenceScreenCreator)
- ?: return createPreferenceScreenFromResource()
-
+ getPreferenceScreenCreator(context) ?: return createPreferenceScreenFromResource()
val preferenceBindingFactory = screenCreator.preferenceBindingFactory
val preferenceHierarchy = screenCreator.getPreferenceHierarchy(context)
val preferenceScreen =
@@ -73,17 +68,14 @@
return preferenceScreen
}
- /**
- * Returns if preference screen metadata can be used to set up preference screen.
- *
- * This is for flagging purpose. If false (e.g. flag is disabled), xml resource is used to build
- * preference screen.
- */
- protected open fun usePreferenceScreenMetadata(): Boolean = false
-
/** Returns the xml resource to create preference screen. */
@XmlRes protected open fun getPreferenceScreenResId(context: Context): Int = 0
+ protected fun getPreferenceScreenCreator(context: Context): PreferenceScreenCreator? =
+ (PreferenceScreenRegistry[getPreferenceScreenBindingKey(context)]
+ as? PreferenceScreenCreator)
+ ?.run { if (isFlagEnabled(context)) this else null }
+
override fun getPreferenceScreenBindingKey(context: Context): String? =
arguments?.getString(EXTRA_BINDING_SCREEN_KEY)
@@ -91,19 +83,4 @@
preferenceScreenBindingHelper?.close()
super.onDestroy()
}
-
- companion object {
- /** Returns [PreferenceFragment] instance to display the preference screen of given key. */
- fun of(screenKey: String): PreferenceFragment? {
- val screenMetadata = PreferenceScreenRegistry[screenKey] ?: return null
- if (
- screenMetadata is PreferenceScreenCreator && screenMetadata.hasCompleteHierarchy()
- ) {
- return PreferenceFragment().apply {
- arguments = Bundle().apply { putString(EXTRA_BINDING_SCREEN_KEY, screenKey) }
- }
- }
- return null
- }
- }
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 1963b15..f072de8 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Hierdie tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokluidspreker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Eksterne toestel"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Gekoppelde toestel"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Geaktiveer"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Jou toestel moet herselflaai om hierdie verandering toe te pas. Herselflaai nou of kanselleer."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade oorfone"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Af"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Diensverskaffernetwerk verander tans"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 002d3bc..86f21d3 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ይህ ጡባዊ"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"የመትከያ ድምፅ ማውጫ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"የውጭ መሣሪያ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"የተገናኘ መሣሪያ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ነቅቷል"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"የእርስዎን መሣሪያ ይህ ለው ለማመልከት እንደገና መነሣት አለበት። አሁን እንደገና ያስነሡ ወይም ይተዉት።"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ባለገመድ ጆሮ ማዳመጫ"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"አብራ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"አጥፋ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"የአገልግሎት አቅራቢ አውታረ መረብን በመቀየር ላይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index a459a86..39219f4 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"هذا الجهاز اللوحي"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"مكبّر صوت بقاعدة إرساء"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"جهاز خارجي"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"جهاز متّصل"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"مفعّلة"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"إيقاف"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"جارٍ تغيير شبكة مشغِّل شبكة الجوّال."</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 6f6dce7..ae27622 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"এই টেবলেটটো"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ড’ক স্পীকাৰ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"বাহ্যিক ডিভাইচ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"সংযোগ হৈ থকা ডিভাইচ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"সক্ষম কৰা আছে"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই সলনিটো কার্যকৰী হ’বলৈ আপোনাৰ ডিভাইচটো ৰিবুট কৰিবই লাগিব। এতিয়াই ৰিবুট কৰক অথবা বাতিল কৰক।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তাঁৰযুক্ত হেডফ\'ন"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"অন"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"অফ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"বাহক নেটৱৰ্কৰ পৰিৱৰ্তন"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 8cc67cb..843c1be 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Bu planşet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok dinamiki"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Xarici cihaz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Qoşulmuş cihaz"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Naqilli qulaqlıq"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator şəbəkəsinin dəyişilməsi"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3688d0c..f906634 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik bazne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Spoljni uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate da restartujete uređaj da bi se ova promena primenila. Restartujte ga odmah ili otkažite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Promena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index f4f5331..613b744 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Гэты планшэт"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Дынамік док-станцыі"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Знешняя прылада"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Падключаная прылада"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Уключана"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Перазагрузіце прыладу, каб прымяніць гэта змяненне. Перазагрузіце ці скасуйце."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Правадныя навушнікі"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Уключана"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выключана"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Змяненне аператара сеткі"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index dd16fc9..767be33 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Този таблет"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Високоговорител докинг станция"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Външно устройство"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Свързано устройство"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Активирано"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да бъде приложена тази промяна, устройството ви трябва да бъде рестартирано. Рестартирайте сега или анулирайте."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Слушалки с кабел"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Включване"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Изключване"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Промяна на мрежата на оператора"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 6b37717..8419544 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"এই ট্যাবলেট"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ডক স্পিকার"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"এক্সটার্নাল ডিভাইস"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"কানেক্ট থাকা ডিভাইস"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"চালু করা আছে"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই পরিবর্তনটি প্রয়োগ করার জন্য আপনার ডিভাইসটি অবশ্যই রিবুট করতে হবে। এখনই রিবুট করুন বা বাতিল করুন।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তার যুক্ত হেডফোন"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"চালু আছে"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"বন্ধ আছে"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"পরিষেবা প্রদানকারীর নেটওয়ার্ক পরিবর্তন করা হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index cb71f25..12e8c73 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate ponovo pokrenuti uređaj da se ova promjena primijeni. Ponovo pokrenite odmah ili otkažite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključi"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključi"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 84eb51f..44780d3 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Aquesta tauleta"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base d\'altaveu"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositiu extern"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositiu connectat"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Has de reiniciar el teu dispositiu perquè s\'apliquin els canvis. Reinicia\'l ara o cancel·la."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculars amb cable"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activa"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactiva"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"S\'està canviant la xarxa de l\'operador de telefonia mòbil"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a8764b6..cadb170 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tento tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externí zařízení"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Připojené zařízení"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuto"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aby se tato změna projevila, je třeba zařízení restartovat. Restartujte zařízení nebo zrušte akci."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelová sluchátka"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnout"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnout"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Probíhá změna sítě operátora"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 697802e..d3b064c 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Denne tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockhøjttaler"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhed"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Forbundet enhed"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiveret"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Din enhed skal genstartes for at anvende denne ændring. Genstart nu, eller annuller."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Høretelefoner med ledning"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Til"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Fra"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Skift af mobilnetværk"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index cb745fc..50bc9cc 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Dieses Tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock-Lautsprecher"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externes Gerät"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbundenes Gerät"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiviert"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Damit diese Änderung übernommen wird, musst du dein Gerät neu starten. Du kannst es jetzt neu starten oder den Vorgang abbrechen."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelgebundene Kopfhörer"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"An"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Aus"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilfunknetzwerk wird gewechselt"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 89817dd..ea6b3ba 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Αυτό το tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Ηχείο βάσης σύνδεσης"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Εξωτερική συσκευή"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Συνδεδεμένη συσκευή"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ενεργή"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Για να εφαρμοστεί αυτή η αλλαγή, θα πρέπει να επανεκκινήσετε τη συσκευή σας. Επανεκκίνηση τώρα ή ακύρωση."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ενσύρματα ακουστικά"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ενεργό"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ανενεργό"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Αλλαγή δικτύου εταιρείας κινητής τηλεφωνίας"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index b6e41c4..03e505a 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index be5dfaa..9fce566 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Carrier network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index b6e41c4..03e505a 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index b6e41c4..03e505a 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 92af284..85cf936 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"This tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dock speaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Connected device"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Carrier network changing"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index ff69f64..3feee4c 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -564,8 +564,7 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas y recordatorios"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite que esta app establezca alarmas y programe acciones para horarios específicos. De esta manera, la app puede ejecutarse en segundo plano, lo que podría aumentar el consumo de batería.\n\nSi se desactiva este permiso, no funcionarán las alarmas ni los eventos basados en el tiempo existentes que programe esta app."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarma, recordatorio, reloj"</string>
- <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
- <skip />
+ <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"No interrumpir"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"No interrumpir"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activar No interrumpir"</string>
@@ -585,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Bocina de la estación de carga"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -686,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Debes reiniciar el dispositivo para que se aplique el cambio. Reinícialo ahora o cancela la acción."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de proveedor de red"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index e2d3589..d2c7a02 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -564,8 +564,7 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas y recordatorios"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite que esta aplicación programe alarmas y otras acciones que se llevan a cabo a una hora determinada. Esto hace que la aplicación pueda seguir activa en segundo plano, lo que puede usar más batería.\n\nSi este permiso está desactivado, no funcionarán las alarmas ni los eventos que se activan a una hora determinada que programe esta aplicación."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarma, recordatorio, reloj"</string>
- <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
- <skip />
+ <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"No molestar"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"No molestar"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activar el modo No molestar"</string>
@@ -585,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altavoz de la base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -686,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Es necesario reiniciar tu dispositivo para que se apliquen los cambios. Reinicia ahora o cancela la acción."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivado"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambiando la red del operador"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 8f7c4a7..1452a0e 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"See tahvelarvuti"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doki kõlar"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Väline seade"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ühendatud seade"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Lubatud"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Selle muudatuse rakendamiseks tuleb seade taaskäivitada. Taaskäivitage kohe või tühistage."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Juhtmega kõrvaklapid"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Sees"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Väljas"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaatori võrku muudetakse"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 7285547..2d97bbf 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tableta hau"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Oinarri bozgorailuduna"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kanpoko gailua"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Konektatutako gailua"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Gaituta"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aldaketa aplikatzeko, berrabiarazi egin behar da gailua. Berrabiaraz ezazu orain, edo utzi bertan behera."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Entzungailu kableduna"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktibatu"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desaktibatu"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operadorearen sarea aldatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index ff0ad1d..11dcc99 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"این رایانه لوحی"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"بلندگوی پایه اتصال"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"دستگاه خارجی"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"دستگاه متصل"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاه باید بازراهاندازی شود. یا اکنون بازراهاندازی کنید یا لغو کنید."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"هدفون سیمی"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"روشن"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"خاموش"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"تغییر شبکه شرکت مخابراتی"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 800f327..4ee5c60 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tämä tabletti"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Telinekaiutin"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ulkoinen laite"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Yhdistetty laite"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Käytössä"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Laitteesi on käynnistettävä uudelleen, jotta muutos tulee voimaan. Käynnistä uudelleen nyt tai peru."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Langalliset kuulokkeet"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Päällä"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ei käytössä"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaattorin verkko muuttuu"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index f36b5f0..d975f3e 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Cette tablette"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur du socle"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Votre appareil doit être redémarré pour que ce changement prenne effet. Redémarrez-le maintenant ou annulez la modification."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Écouteurs filaires"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activé"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Désactivé"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Changer de réseau de fournisseur de services"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 4327708..c987bc4 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -564,8 +564,7 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes et rappels"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Autoriser cette appli à définir des alarmes et à programmer des actions à certaines heures. Elle s\'exécutera alors en arrière-plan, ce qui peut solliciter davantage la batterie.\n\nSi l\'autorisation est désactivée, les alarmes existantes et les événements programmés par l\'appli ne fonctionneront pas."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"définir, alarme, rappel, horloge"</string>
- <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
- <skip />
+ <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Ne pas déranger"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ne pas déranger"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activer"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activer le mode Ne pas déranger"</string>
@@ -585,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Cette tablette"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Haut-parleur station d\'accueil"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Appareil externe"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Appareil connecté"</string>
@@ -686,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Vous devez redémarrer l\'appareil pour que cette modification soit appliquée. Redémarrez maintenant ou annulez l\'opération."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Casque filaire"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Allumé"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Éteint"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Modification du réseau de l\'opérateur"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index bac62f2..0216ad9 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Esta tableta"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altofalante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necesario reiniciar o teu dispositivo para aplicar este cambio. Reiníciao agora ou cancela o cambio."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activada"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivada"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de rede do operador"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 9af8e48..bc34173 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"આ ટૅબ્લેટ"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ડૉક સ્પીકર"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"બહારનું ડિવાઇસ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"કનેક્ટ કરેલું ડિવાઇસ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ચાલુ છે"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"આ ફેરફારને લાગુ કરવા માટે તમારા ડિવાઇસને રીબૂટ કરવાની જરૂર છે. હમણાં જ રીબૂટ કરો કે રદ કરો."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"વાયરવાળો હૅડફોન"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ચાલુ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"બંધ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"કૅરીઅર નેટવર્કમાં ફેરફાર થઈ રહ્યો છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 785ef59..25309b3e 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"यह टैबलेट"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाहरी डिवाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट किया गया डिवाइस"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"चालू है"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"बदली गई सेटिंग को लागू करने के लिए, डिवाइस को रीस्टार्ट करना होगा. अपने डिवाइस को रीस्टार्ट करें या रद्द करें."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर वाला हेडफ़ोन"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"चालू है"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद है"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"मोबाइल और इंटरनेट सेवा देने वाली कंपनी का नेटवर्क बदल रहा है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 107c561..516834d 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ovaj tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvučnik priključne stanice"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Vanjski uređaj"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezani uređaj"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Uređaj se mora ponovno pokrenuti da bi se ta promjena primijenila. Ponovo pokrenite uređaj odmah ili odustanite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index dff22d9..1d2b715 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ez a táblagép"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhangszóró"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Külső eszköz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Csatlakoztatott eszköz"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Engedélyezve"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Az eszközt újra kell indítani, hogy a módosítás megtörténjen. Indítsa újra most, vagy vesse el a módosítást."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vezetékes fejhallgató"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Be"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ki"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Szolgáltatói hálózat váltása"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 60e5adf..85b5548 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Այս պլանշետը"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Դոկ-կայանով բարձրախոս"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Արտաքին սարք"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Միացված սարք"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Միացված է"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Սարքն անհրաժեշտ է վերագործարկել, որպեսզի փոփոխությունը կիրառվի։ Վերագործարկեք հիմա կամ չեղարկեք փոփոխությունը։"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Լարով ականջակալ"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Միացնել"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Անջատել"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Օպերատորի ցանցի փոփոխություն"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index f0b76ce..6660188 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tablet ini"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker dok"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Perangkat Eksternal"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Perangkat yang terhubung"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktif"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Perangkat Anda harus di-reboot agar perubahan ini diterapkan. Reboot sekarang atau batalkan."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Headphone berkabel"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktif"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Nonaktif"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Jaringan operator berubah"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 61813a3..0984892 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Þessi spjaldtölva"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Hátalaradokka"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ytra tæki"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tengt tæki"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Virkt"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Endurræsa þarf tækið til að þessi breyting taki gildi. Endurræstu núna eða hættu við."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Heyrnartól með snúru"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Kveikt"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Slökkt"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Skiptir um farsímakerfi"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 10394f1..e70c415 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -564,8 +564,7 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Sveglie e promemoria"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Consenti a questa app di impostare sveglie e programmare azioni per orari specifici. L\'app potrà essere eseguita in background, comportando un consumo maggiore della batteria.\n\nSe questa autorizzazione viene disattivata, le sveglie esistenti e gli eventi basati sull\'orario programmati da questa app non funzioneranno."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programmare, sveglia, promemoria, orologio"</string>
- <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
- <skip />
+ <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Non disturbare"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Non disturbare"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Attiva"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Attiva Non disturbare"</string>
@@ -585,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Questo tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Base con altoparlante"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo esterno"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo connesso"</string>
@@ -686,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Attivo"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Per applicare questa modifica, devi riavviare il dispositivo. Riavvia ora o annulla."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Cuffie con cavo"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio della rete dell\'operatore"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c0f1e87..662455d 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"הטאבלט הזה"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"רמקול של אביזר העגינה"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"מכשיר חיצוני"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"המכשיר המחובר"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"מופעל"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"צריך להפעיל מחדש את המכשיר כדי להחיל את השינוי. יש להפעיל מחדש עכשיו או לבטל."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות חוטיות"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"פועלת"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"מצב כבוי"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"רשת ספק משתנה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 71aae44..70fc2d0 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"このタブレット"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ホルダー スピーカー"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部デバイス"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"接続済みのデバイス"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"有効"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"この変更を適用するには、デバイスの再起動が必要です。今すぐ再起動するか、キャンセルしてください。"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線ヘッドフォン"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ON"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"OFF"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"携帯通信会社のネットワークを変更します"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 7801417..040c046 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ამ ტაბლეტზე"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"სამაგრის დინამიკი"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"გარე მოწყობილობა"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"დაკავშირებული მოწყობილობა"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ჩართული"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ამ ცვლილების ასამოქმედებლად თქვენი მოწყობილობა უნდა გადაიტვირთოს. გადატვირთეთ ახლავე ან გააუქმეთ."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"სადენიანი ყურსასმენი"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ჩართვა"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"გამორთვა"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ოპერატორის ქსელის შეცვლა"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 2ae8250..f54067c 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Осы планшет"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамигі бар қондыру станциясы"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Сыртқы құрылғы"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Жалғанған құрылғы"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Қосулы"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бұл өзгеріс күшіне енуі үшін, құрылғыны қайта жүктеу керек. Қазір қайта жүктеңіз не бас тартыңыз."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Сымды құлақаспап"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Қосу"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өшіру"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор желісін өзгерту"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 85801c9..807e7e2 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ថេប្លេតនេះ"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ឧបាល័រជើងទម្រ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ឧបករណ៍ខាងក្រៅ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ឧបករណ៍ដែលបានភ្ជាប់"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"បានបើក"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ត្រូវតែចាប់ផ្ដើមឧបករណ៍របស់អ្នកឡើងវិញ ដើម្បីឱ្យការផ្លាស់ប្ដូរនេះមានប្រសិទ្ធភាព។ ចាប់ផ្ដើមឡើងវិញឥឡូវនេះ ឬបោះបង់។"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"កាសមានខ្សែ"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"បើក"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"បិទ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"បណ្តាញក្រុមហ៊ុនសេវាទូរសព្ទកំពុងផ្លាស់ប្តូរ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 6dc3ae9..23e31c2 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ಈ ಟ್ಯಾಬ್ಲೆಟ್"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ಡಾಕ್ ಸ್ಪೀಕರ್"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ಬಾಹ್ಯ ಸಾಧನ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ಕನೆಕ್ಟ್ ಮಾಡಿರುವ ಸಾಧನ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ಈ ಬದಲಾವಣೆ ಅನ್ವಯವಾಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ರೀಬೂಟ್ ಮಾಡಬೇಕು. ಇದೀಗ ರೀಬೂಟ್ ಮಾಡಿ ಅಥವಾ ರದ್ದುಗೊಳಿಸಿ."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ವೈಯರ್ ಹೊಂದಿರುವ ಹೆಡ್ಫೋನ್"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ಆನ್ ಆಗಿದೆ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ಆಫ್"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ವಾಹಕ ನೆಟ್ವರ್ಕ್ ಬದಲಾಯಿಸುವಿಕೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 14e8f4f..cfbddad 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"이 태블릿"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"도크 스피커"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"외부 기기"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"연결된 기기"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"사용 설정됨"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"변경사항을 적용하려면 기기를 재부팅해야 합니다. 지금 재부팅하거나 취소하세요."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"유선 헤드폰"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"사용"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"사용 안 함"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"이동통신사 네트워크 변경"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 9ff62cf..c5a3bcc 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ушул планшет"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док бекеттин динамиги"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Тышкы түзмөк"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Туташкан түзмөк"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Күйүк"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бул өзгөрүү күчүнө кириши үчүн, түзмөктү өчүрүп күйгүзүңүз. Азыр же кийинчерээк өчүрүп күйгүзсөңүз болот."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Зымдуу гарнитура"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Күйгүзүү"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өчүрүү"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Байланыш оператору өзгөртүлүүдө"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 5d5a4c6..70fd196 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ແທັບເລັດນີ້"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ແທ່ນວາງລຳໂພງ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ອຸປະກອນພາຍນອກ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ອຸປະກອນທີ່ເຊື່ອມຕໍ່"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ເປີດການນຳໃຊ້ແລ້ວ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ທ່ານຕ້ອງປິດເປີດອຸປະກອນຄືນໃໝ່ເພື່ອນຳໃຊ້ການປ່ຽນແປງນີ້. ປິດເປີດໃໝ່ດຽວນີ້ ຫຼື ຍົກເລີກ."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ຫູຟັງແບບມີສາຍ"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ເປີດ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ປິດ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ການປ່ຽນເຄືອຂ່າຍຜູ້ໃຫ້ບໍລິການ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 2b0b71d..5488437 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Šis planšetinis kompiuteris"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doko garsiakalbis"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Išorinis įrenginys"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Prijungtas įrenginys"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Įgalinta"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kad pakeitimas būtų pritaikytas, įrenginį reikia paleisti iš naujo. Dabar paleiskite iš naujo arba atšaukite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Laidinės ausinės"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Įjungta"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Išjungta"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Keičiamas operatoriaus tinklas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index a8a4ea0..faf7b5f 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Šis planšetdators"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Doka skaļrunis"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ārēja ierīce"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pievienotā ierīce"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Iespējots"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Lai šīs izmaiņas tiktu piemērotas, nepieciešama ierīces atkārtota palaišana. Atkārtoti palaidiet to tūlīt vai atceliet izmaiņas."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vadu austiņas"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ieslēgts"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izslēgts"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilo sakaru operatora tīkla mainīšana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 923ea5c..2f215e8 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Овој таблет"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Док со звучник"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Надворешен уред"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Поврзан уред"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да се примени променава, уредот мора да се рестартира. Рестартирајте сега или откажете."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичени слушалки"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вклучено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Исклучено"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Променување на мрежата на операторот"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 05579fe..859ac3b 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ഈ ടാബ്ലെറ്റ്"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ഡോക്ക് സ്പീക്കർ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ബാഹ്യ ഉപകരണം"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"കണക്റ്റ് ചെയ്ത ഉപകരണം"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"പ്രവർത്തനക്ഷമമാക്കി"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ഈ മാറ്റം ബാധകമാകുന്നതിന് നിങ്ങളുടെ ഉപകരണം റീബൂട്ട് ചെയ്യേണ്ടതുണ്ട്. ഇപ്പോൾ റീബൂട്ട് ചെയ്യുകയോ റദ്ദാക്കുകയോ ചെയ്യുക."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയേർഡ് ഹെഡ്ഫോൺ"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ഓണാണ്"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ഓഫാണ്"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"കാരിയർ നെറ്റ്വർക്ക് മാറ്റൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 8957a2b..7615dcc 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Энэ таблет"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Суурилуулагчийн чанга яригч"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Гадаад төхөөрөмж"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Холбогдсон төхөөрөмж"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл цуцлана уу."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Утастай чихэвч"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Асаах"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Унтраах"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор компанийн сүлжээг өөрчилж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 36b967e..fb90ce3 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"हा टॅबलेट"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डॉक स्पीकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिव्हाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट केलेले डिव्हाइस"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सुरू केले आहे"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"हा बदल लागू करण्यासाठी तुमचे डिव्हाइस रीबूट करणे आवश्यक आहे. आता रीबूट करा किंवा रद्द करा."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर असलेला हेडफोन"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"सुरू करा"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद करा"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"वाहक नेटवर्क बदलत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 2db04be..acd8487 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tablet ini"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Pembesar suara dok"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Peranti Luar"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Peranti yang disambungkan"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Didayakan"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Peranti anda mesti dibut semula supaya perubahan ini berlaku. But semula sekarang atau batalkan."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fon kepala berwayar"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Hidup"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Mati"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Rangkaian pembawa berubah"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 660fd14..2640c3a 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ဤတက်ဘလက်"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"အထိုင် စပီကာ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ပြင်ပစက်"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ချိတ်ဆက်ကိရိယာ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ဖွင့်ထားသည်"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ဤအပြောင်းအလဲ ထည့်သွင်းရန် သင့်စက်ကို ပြန်လည်စတင်ရမည်။ ယခု ပြန်လည်စတင်ပါ သို့မဟုတ် ပယ်ဖျက်ပါ။"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ကြိုးတပ်နားကြပ်"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ဖွင့်"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ပိတ်"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ဝန်ဆောင်မှုပေးသူ ကွန်ရက် ပြောင်းလဲနေသည်။"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 3e5d141..4a53090 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Dette nettbrettet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dokkhøyttaler"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Ekstern enhet"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Tilkoblet enhet"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Slått på"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten din må startes på nytt for at denne endringen skal tre i kraft. Start på nytt nå eller avbryt."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"hodetelefoner med kabel"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Bytting av operatørnettverk"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index ad28882..a04028f 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"यो ट्याब्लेट"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"डक स्पिकर"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"बाह्य डिभाइस"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"कनेक्ट गरिएको डिभाइस"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सक्षम पारिएको छ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"यो परिवर्तन लागू गर्न तपाईंको यन्त्र अनिवार्य रूपमा रिबुट गर्नु पर्छ। अहिले रिबुट गर्नुहोस् वा रद्द गर्नुहोस्।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"तारसहितको हेडफोन"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"अन छ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"अफ छ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"सेवा प्रदायकको नेटवर्क परिवर्तन गर्ने आइकन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 0fcc6fe..c3998c5 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Deze tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockspeaker"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern apparaat"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Verbonden apparaat"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aan"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Je apparaat moet opnieuw worden opgestart om deze wijziging toe te passen. Start nu opnieuw op of annuleer de wijziging."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade koptelefoon"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Uit"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Netwerk van provider wordt gewijzigd"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 694d034..676a426 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ଏହି ଟାବଲେଟ"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ଡକ ସ୍ପିକର"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ଏକ୍ସଟର୍ନଲ ଡିଭାଇସ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"କନେକ୍ଟ କରାଯାଇଥିବା ଡିଭାଇସ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ସକ୍ଷମ କରାଯାଇଛି"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ଏହି ପରିବର୍ତ୍ତନ ଲାଗୁ କରିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ନିଶ୍ଚିତ ରୂପେ ରିବୁଟ୍ କରାଯିବା ଆବଶ୍ୟକ। ବର୍ତ୍ତମାନ ରିବୁଟ୍ କରନ୍ତୁ କିମ୍ବା ବାତିଲ କରନ୍ତୁ।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ତାରଯୁକ୍ତ ହେଡଫୋନ୍"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ଚାଲୁ ଅଛି"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ବନ୍ଦ ଅଛି"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"କେରିଅର୍ ନେଟ୍ୱର୍କ ବଦଳୁଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index d0cf820..4ef2308c 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ਇਹ ਟੈਬਲੈੱਟ"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ਡੌਕ ਸਪੀਕਰ"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ਬਾਹਰੀ ਡੀਵਾਈਸ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"ਕਨੈਕਟ ਕੀਤਾ ਡੀਵਾਈਸ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ਇਸ ਤਬਦੀਲੀ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਰੀਬੂਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ। ਹੁਣੇ ਰੀਬੂਟ ਕਰੋ ਜਾਂ ਰੱਦ ਕਰੋ।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ਤਾਰ ਵਾਲੇ ਹੈੱਡਫ਼ੋਨ"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ਚਾਲੂ"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ਬੰਦ"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"ਕੈਰੀਅਰ ਨੈੱਟਵਰਕ ਦੀ ਬਦਲੀ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index c6d78f6..3693c38 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ten tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Głośnik ze stacją dokującą"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Urządzenie zewnętrzne"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Połączone urządzenie"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Włączono"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Wprowadzenie zmiany wymaga ponownego uruchomienia urządzenia. Uruchom ponownie teraz lub anuluj."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Słuchawki przewodowe"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Włączono"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Wyłączono"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Zmiana sieci operatora"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 98bda85..75ffcd1 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 20acb00..535261b 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altifalante estação carregamento"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo associado"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativada"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reiniciar o dispositivo para aplicar esta alteração. Reinicie agora ou cancele."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auscultadores com fios"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ligado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desligado"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Rede do operador em mudança."</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 98bda85..75ffcd1 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Este tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Alto-falante da base"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispositivo externo"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispositivo conectado"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index a6d17c1..242127e 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Această tabletă"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Difuzorul dispozitivului de andocare"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Dispozitiv extern"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Dispozitiv conectat"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să repornești dispozitivul. Repornește-l acum sau anulează."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Căști cu fir"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activat"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Dezactivat"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Se schimbă rețeaua operatorului"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 838b5ed..2ac0128 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Этот планшет"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Колонка с док-станцией"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Внешнее устройство"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Подключенное устройство"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Включено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Чтобы изменение вступило в силу, необходимо перезапустить устройство. Вы можете сделать это сейчас или позже."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Проводные наушники"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вкл."</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выкл."</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Сменить сеть"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index cc7a45e..f8565c4 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"මෙම ටැබ්ලටය"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ඩොක් ස්පීකරය"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"බාහිර උපාංගය"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"සම්බන්ධ කළ උපාංගය"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"සබලයි"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"මෙම වෙනස යෙදීමට ඔබේ උපාංගය නැවත පණ ගැන්විය යුතුය. දැන් නැවත පණ ගන්වන්න හෝ අවලංගු කරන්න."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"රැහැන්ගත කළ හෙඩ්ෆෝන්"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ක්රියාත්මකයි"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ක්රියාවිරහිතයි"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"වාහක ජාලය වෙනස් වෙමින්"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 43db02b..00bb994 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Tento tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Reproduktor doku"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Externé zariadenie"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pripojené zariadenie"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuté"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Zmena sa prejaví až po reštarte zariadenia. Môžete ho teraz reštartovať alebo akciu zrušiť."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Slúchadlá s káblom"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnúť"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnúť"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mení sa sieť operátora"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index ddd0fb2..5bce9fa 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ta tablični računalnik"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Zvočnik nosilca"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Zunanja naprava"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Povezana naprava"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogočeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Napravo je treba znova zagnati, da bo ta sprememba uveljavljena. Znova zaženite zdaj ali prekličite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žične slušalke"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vklop"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izklop"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Spreminjanje omrežja operaterja"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 3831cf4..59472e3 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ky tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Altoparlanti i stacionit"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Pajisja e jashtme"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Pajisja e lidhur"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pajisja jote duhet të riniset që ky ndryshim të zbatohet. Rinise tani ose anuloje."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kufje me tela"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktive"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Joaktive"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Rrjeti i operatorit celular po ndryshohet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 73794bd..57e2a0a 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Овај таблет"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Звучник базне станице"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Спољни уређај"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Повезани уређај"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Омогућено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Морате да рестартујете уређај да би се ова промена применила. Рестартујте га одмах или откажите."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичане слушалице"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Укључено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Искључено"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Промена мреже мобилног оператера"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index f47bdab..a3eaee1 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Den här surfplattan"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dockningsstationens högtalare"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Extern enhet"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ansluten enhet"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiverat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten måste startas om för att ändringen ska börja gälla. Starta om nu eller avbryt."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hörlurar med sladd"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Byter leverantörsnätverk"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 02db3e1..9979a9d 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Kishikwambi hiki"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Spika ya kituo"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Kifaa cha Nje"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Kifaa kilichounganishwa"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vya waya"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Umewashwa"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Umezimwa"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mabadiliko katika mtandao wa mtoa huduma"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index a5a96f2..18a3186 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"இந்த டேப்லெட்"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"டாக் ஸ்பீக்கர்"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"வெளிப்புறச் சாதனம்"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"இணைக்கப்பட்டுள்ள சாதனம்"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"இயக்கப்பட்டது"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"இந்த மாற்றங்கள் செயல்படுத்தப்பட உங்கள் சாதனத்தை மறுபடி தொடங்க வேண்டும். இப்போதே மறுபடி தொடங்கவும் அல்லது ரத்துசெய்யவும்."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"வயருள்ள ஹெட்ஃபோன்"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ஆன்"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ஆஃப்"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"மொபைல் நிறுவன நெட்வொர்க்கை மாற்றும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 5577389..f883796 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"ఈ టాబ్లెట్"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"డాక్ స్పీకర్"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"ఎక్స్టర్నల్ పరికరం"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"కనెక్ట్ చేసిన పరికరం"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ఎనేబుల్ చేయబడింది"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ఈ మార్పును వర్తింపజేయాలంటే మీరు మీ పరికరాన్ని తప్పనిసరిగా రీబూట్ చేయాలి. ఇప్పుడే రీబూట్ చేయండి లేదా రద్దు చేయండి."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"వైర్ ఉన్న హెడ్ఫోన్"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ఆన్లో ఉంది"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ఆఫ్లో ఉంది"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"క్యారియర్ నెట్వర్క్ మారుతోంది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 48087c2..e56656b 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"แท็บเล็ตเครื่องนี้"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"แท่นชาร์จที่มีลำโพง"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"อุปกรณ์ภายนอก"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"อุปกรณ์ที่เชื่อมต่อ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"เปิดใช้"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"คุณต้องรีบูตอุปกรณ์เพื่อให้การเปลี่ยนแปลงนี้มีผล รีบูตเลยหรือยกเลิก"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"หูฟังแบบมีสาย"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"เปิด"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ปิด"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"การเปลี่ยนเครือข่ายผู้ให้บริการ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 34d51d44..3e9f2387 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Ang tablet na ito"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Speaker ng dock"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"External na Device"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Nakakonektang device"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Na-enable"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Dapat i-reboot ang iyong device para mailapat ang pagbabagong ito. Mag-reboot ngayon o kanselahin."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired na headphone"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Naka-on"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Naka-off"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Nagpapalit ng carrier network"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 9b5cc292..22c0ab1 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Bu tablet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Yuva hoparlörü"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Harici Cihaz"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Bağlı cihaz"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Etkin"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu değişikliğin geçerli olması için cihazınızın yeniden başlatılması gerekir. Şimdi yeniden başlatın veya iptal edin."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kablolu kulaklık"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Açık"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Kapalı"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operatör ağı değiştiriliyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index a396798..50ebd24 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Цей планшет"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Динамік док-станції"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Зовнішній пристрій"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Підключений пристрій"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Увімкнено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Щоб застосувати ці зміни, потрібний перезапуск. Перезапустіть пристрій або скасуйте зміни."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Дротові навушники"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Увімкнено"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Вимкнено"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Змінення мережі оператора"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index c60a58b..d6dd2c8 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"یہ ٹیبلیٹ"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"ڈاک اسپیکر"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"بیرونی آلہ"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"منسلک آلہ"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"اس تبدیلی کو لاگو کرنے کے ليے آپ کے آلہ کو ریبوٹ کرنا ضروری ہے۔ ابھی ریبوٹ کریں یا منسوخ کریں۔"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"وائرڈ ہیڈ فون"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"آن"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"آف"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"کیریئر نیٹ ورک کی تبدیلی"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 3beb514..1e3d64f3 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Shu planshet"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Dok-stansiyali karnay"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Tashqi qurilma"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Ulangan qurilma"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Yoniq"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Oʻzgarishlar kuchga kirishi uchun qurilmani oʻchirib yoqing. Buni hozir yoki keyinroq bajarishingiz mumkin."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli quloqlik"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Yoniq"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Oʻchiq"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobil tarmoqni o‘zgartirish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index d3152f4..95092ff 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Máy tính bảng này"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Loa có gắn đế"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Thiết bị bên ngoài"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Thiết bị đã kết nối"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Đã bật"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bạn phải khởi động lại thiết bị để áp dụng sự thay đổi này. Hãy khởi động lại ngay hoặc hủy."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Tai nghe có dây"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Đang bật"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Đang tắt"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Thay đổi mạng của nhà mạng"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 964c3da..fb9e7b1 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"这部平板电脑"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"基座音箱"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部设备"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"连接的设备"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已启用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"设备必须重新启动才能应用此更改。您可以立即重新启动或取消。"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有线耳机"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"开启"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"关闭"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"运营商网络正在更改"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index a35b9f2..9c6da5f 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"此平板電腦"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"插座喇叭"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連接的裝置"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"你的裝置必須重新開機,才能套用此變更。請立即重新開機或取消。"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"流動網絡供應商網絡正在變更"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 274767b..501b088 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"這台平板電腦"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"座架喇叭"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"外部裝置"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"已連結的裝置"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"裝置必須重新啟動才能套用這項變更。請立即重新啟動或取消變更。"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"電信業者網路正在進行變更"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 9ccb261..4f875de 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -584,6 +584,8 @@
<string name="media_transfer_this_device_name_tablet" msgid="2975593806278422086">"Le thebhulethi"</string>
<!-- no translation found for media_transfer_this_device_name_tv (5285685336836896535) -->
<skip />
+ <!-- no translation found for media_transfer_internal_mic (797333824290228595) -->
+ <skip />
<string name="media_transfer_dock_speaker_device_name" msgid="2856219597113881950">"Isipikha sentuba"</string>
<string name="media_transfer_external_device_name" msgid="2588672258721846418">"Idivayisi Yangaphandle"</string>
<string name="media_transfer_default_device_name" msgid="4315604017399871828">"Idivayisi exhunyiwe"</string>
@@ -685,6 +687,10 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kufanele idivayisi yakho iqaliswe ukuze lolu shintsho lusebenze. Qalisa manje noma khansela."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ama-headphone anentambo"</string>
+ <!-- no translation found for media_transfer_wired_device_mic_name (7417067197803840965) -->
+ <skip />
+ <!-- no translation found for media_transfer_usb_device_mic_name (9189914846215516322) -->
+ <skip />
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vuliwe"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Valiwe"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Inethiwekhi yenkampani yenethiwekhi iyashintsha"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java
deleted file mode 100644
index 7994924..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/ObservablePreferenceFragment.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settingslib.core.lifecycle;
-
-
-import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
-import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
-import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
-import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
-import static androidx.lifecycle.Lifecycle.Event.ON_START;
-import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
-
-import android.annotation.CallSuper;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-import androidx.lifecycle.LifecycleOwner;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settingslib.preference.PreferenceFragment;
-
-/**
- * Preference fragment that has hooks to observe fragment lifecycle events.
- */
-public abstract class ObservablePreferenceFragment extends PreferenceFragment
- implements LifecycleOwner {
-
- private final Lifecycle mLifecycle = new Lifecycle(this);
-
- public Lifecycle getSettingsLifecycle() {
- return mLifecycle;
- }
-
- @CallSuper
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- mLifecycle.onAttach(context);
- }
-
- @CallSuper
- @Override
- public void onCreate(Bundle savedInstanceState) {
- mLifecycle.onCreate(savedInstanceState);
- mLifecycle.handleLifecycleEvent(ON_CREATE);
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
- mLifecycle.setPreferenceScreen(preferenceScreen);
- super.setPreferenceScreen(preferenceScreen);
- }
-
- @CallSuper
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- mLifecycle.onSaveInstanceState(outState);
- }
-
- @CallSuper
- @Override
- public void onStart() {
- mLifecycle.handleLifecycleEvent(ON_START);
- super.onStart();
- }
-
- @CallSuper
- @Override
- public void onResume() {
- mLifecycle.handleLifecycleEvent(ON_RESUME);
- super.onResume();
- }
-
- @CallSuper
- @Override
- public void onPause() {
- mLifecycle.handleLifecycleEvent(ON_PAUSE);
- super.onPause();
- }
-
- @CallSuper
- @Override
- public void onStop() {
- mLifecycle.handleLifecycleEvent(ON_STOP);
- super.onStop();
- }
-
- @CallSuper
- @Override
- public void onDestroy() {
- mLifecycle.handleLifecycleEvent(ON_DESTROY);
- super.onDestroy();
- }
-
- @CallSuper
- @Override
- public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
- mLifecycle.onCreateOptionsMenu(menu, inflater);
- super.onCreateOptionsMenu(menu, inflater);
- }
-
- @CallSuper
- @Override
- public void onPrepareOptionsMenu(final Menu menu) {
- mLifecycle.onPrepareOptionsMenu(menu);
- super.onPrepareOptionsMenu(menu);
- }
-
- @CallSuper
- @Override
- public boolean onOptionsItemSelected(final MenuItem menuItem) {
- boolean lifecycleHandled = mLifecycle.onOptionsItemSelected(menuItem);
- if (!lifecycleHandled) {
- return super.onOptionsItemSelected(menuItem);
- }
- return lifecycleHandled;
- }
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
index 548eb3f..874e030 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java
@@ -57,7 +57,7 @@
}
};
- /* package */ InputRouteManager(@NonNull Context context, @NonNull AudioManager audioManager) {
+ public InputRouteManager(@NonNull Context context, @NonNull AudioManager audioManager) {
mContext = context;
mAudioManager = audioManager;
Handler handler = new Handler(context.getMainLooper());
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index 7b2a284..3cc111f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -140,7 +140,7 @@
private static Status computeStatus(@NonNull ZenModeConfig.ZenRule zenRuleExtraData) {
if (zenRuleExtraData.enabled) {
- if (zenRuleExtraData.isAutomaticActive()) {
+ if (zenRuleExtraData.isActive()) {
return Status.ENABLED_AND_ACTIVE;
} else {
return Status.ENABLED;
@@ -241,10 +241,6 @@
formattedTime);
}
}
- // TODO: b/333527800 - For TYPE_SCHEDULE_TIME rules we could do the same; however
- // according to the snoozing discussions the mode may or may not end at the scheduled
- // time if manually activated. When we resolve that point, we could calculate end time
- // for these modes as well.
return getTriggerDescription();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING b/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING
index 71cbcb5..1346ee5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING
+++ b/packages/SettingsLib/src/com/android/settingslib/users/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "SettingsLibTests",
- "options": [
- {
- "include-filter": "com.android.settingslib.users."
- }
- ]
+ "name": "SettingsLibTests_settingslib_users"
}
]
}
\ No newline at end of file
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index c107ff5..1a99d25 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -36,6 +36,7 @@
"aconfig_new_storage_flags_lib",
"aconfigd_java_utils",
"aconfig_demo_flags_java_lib",
+ "configinfra_framework_flags_java_lib",
"device_config_service_flags_java",
"libaconfig_java_proto_lite",
"SettingsLibDeviceStateRotationLock",
diff --git a/packages/SettingsProvider/TEST_MAPPING b/packages/SettingsProvider/TEST_MAPPING
index 0eed2b7..cf9ed2e 100644
--- a/packages/SettingsProvider/TEST_MAPPING
+++ b/packages/SettingsProvider/TEST_MAPPING
@@ -4,12 +4,7 @@
"name": "SettingsProviderTest"
},
{
- "name": "CtsProviderTestCases",
- "options": [
- {
- "include-filter": "android.provider.cts.settings."
- }
- ]
+ "name": "CtsProviderTestCases_cts_settings"
}
],
"postsubmit": [
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index bfbf41d..afbe84c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -99,13 +99,23 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print("SyncDisabledForTests: ");
- MyShellCommand.getSyncDisabledForTests(pw, pw);
+ if (android.provider.flags.Flags.dumpImprovements()) {
+ pw.print("SyncDisabledForTests: ");
+ MyShellCommand.getSyncDisabledForTests(pw, pw);
- pw.print("Is mainline: ");
- pw.println(UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService());
+ pw.print("UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService(): ");
+ pw.println(UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService());
- final IContentProvider iprovider = mProvider.getIContentProvider();
+ pw.println("DeviceConfig provider: ");
+ try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd)) {
+ DeviceConfig.dump(pfd, pw, /* prefix= */ " ", args);
+ } catch (IOException e) {
+ pw.print("IOException creating ParcelFileDescriptor: ");
+ pw.println(e);
+ }
+ }
+
+ IContentProvider iprovider = mProvider.getIContentProvider();
pw.println("DeviceConfig flags:");
for (String line : MyShellCommand.listAll(iprovider)) {
pw.println(line);
@@ -251,13 +261,22 @@
public static HashMap<String, String> getAllFlags(IContentProvider provider) {
HashMap<String, String> allFlags = new HashMap<String, String>();
- for (DeviceConfig.Properties properties : DeviceConfig.getAllProperties()) {
- List<String> keys = new ArrayList<>(properties.getKeyset());
- for (String flagName : properties.getKeyset()) {
- String fullName = properties.getNamespace() + "/" + flagName;
- allFlags.put(fullName, properties.getString(flagName, null));
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ Bundle b = provider.call(new AttributionSource(Process.myUid(),
+ resolveCallingPackage(), null), Settings.AUTHORITY,
+ Settings.CALL_METHOD_LIST_CONFIG, null, args);
+ if (b != null) {
+ Map<String, String> flagsToValues =
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
+ allFlags.putAll(flagsToValues);
}
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
}
+
return allFlags;
}
diff --git a/packages/Shell/TEST_MAPPING b/packages/Shell/TEST_MAPPING
index 9bb1b4b..6b9f1eb 100644
--- a/packages/Shell/TEST_MAPPING
+++ b/packages/Shell/TEST_MAPPING
@@ -1,23 +1,10 @@
{
"presubmit": [
{
- "name": "CtsBugreportTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsBugreportTestCases_android_server_os"
},
{
- "name": "ShellTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ShellTests_android_server_os"
},
{
"name": "CtsUiAutomationTestCases",
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index be4e9a1..cd16af7 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -452,7 +452,7 @@
"tests/src/**/systemui/clipboardoverlay/ClipboardListenerTest.java",
"tests/src/**/systemui/doze/DozeScreenStateTest.java",
"tests/src/**/systemui/keyguard/WorkLockActivityControllerTest.java",
- "tests/src/**/systemui/media/dialog/MediaOutputControllerTest.java",
+ "tests/src/**/systemui/media/dialog/MediaSwitchingControllerTest.java",
"tests/src/**/systemui/navigationbar/views/NavigationBarTest.java",
"tests/src/**/systemui/power/PowerNotificationWarningsTest.java",
"tests/src/**/systemui/power/PowerUITest.java",
@@ -934,9 +934,9 @@
"androidx.compose.runtime_runtime",
],
libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
+ "android.test.runner.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
"truth",
],
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 16dd4e5..07a1e63 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -21,15 +21,7 @@
// v2/android-virtual-infra/test_mapping/presubmit-avd
"presubmit": [
{
- "name": "SystemUIGoogleTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "SystemUIGoogleTests"
},
{
// Permission indicators
@@ -48,15 +40,7 @@
},
{
// Permission indicators
- "name": "CtsVoiceRecognitionTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVoiceRecognitionTestCases"
}
],
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING b/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING
index 4a10108..1820f39 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING
+++ b/packages/SystemUI/accessibility/accessibilitymenu/TEST_MAPPING
@@ -2,12 +2,7 @@
// TODO: b/324945360 - Re-enable on presubmit after fixing failures
"postsubmit": [
{
- "name": "AccessibilityMenuServiceTests",
- "options": [
- {
- "exclude-annotation": "android.support.test.filters.FlakyTest"
- }
- ]
+ "name": "AccessibilityMenuServiceTests"
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 02e8cd6..f3a28ca 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -149,6 +149,16 @@
}
flag {
+ name: "modes_dialog_single_rows"
+ namespace: "systemui"
+ description: "[Experiment] Display one entry per grid row in the Modes Dialog."
+ bug: "366034002"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "pss_app_selector_recents_split_screen"
namespace: "systemui"
description: "Allows recent apps selected for partial screenshare to be launched in split screen mode"
@@ -538,13 +548,6 @@
}
flag {
- name: "haptic_volume_slider"
- namespace: "systemui"
- description: "Adds haptic feedback to the volume slider."
- bug: "316953430"
-}
-
-flag {
name: "new_volume_panel"
namespace: "systemui"
description: "Switches to the new volume panel (without Slices)."
@@ -668,13 +671,6 @@
}
flag {
- name: "compose_lockscreen"
- namespace: "systemui"
- description: "Enables the compose version of lockscreen that runs standalone, outside of Flexiglass."
- bug: "301968149"
-}
-
-flag {
name: "enable_contextual_tip_for_power_off"
namespace: "systemui"
description: "Enables on-screen contextual tip about how to power off or restart phone"
@@ -1313,6 +1309,16 @@
}
flag {
+ name: "sim_pin_bouncer_reset"
+ namespace: "systemui"
+ description: "The SIM PIN bouncer does not close after unlocking"
+ bug: "297461589"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "use_transitions_for_keyguard_occluded"
namespace: "systemui"
description: "Use Keyguard Transitions to set Notification Shade occlusion state"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index 9d0b095..d025275 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -57,6 +57,7 @@
import com.android.systemui.Flags.translucentOccludingActivityFix
import com.android.systemui.animation.TransitionAnimator.Companion.toTransitionState
import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
+import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived
import com.android.wm.shell.shared.IShellTransitions
import com.android.wm.shell.shared.ShellTransitions
import java.util.concurrent.Executor
@@ -607,8 +608,8 @@
* this registration.
*/
fun register(controller: Controller) {
- check(returnAnimationFrameworkLibrary()) {
- "Long-lived registrations cannot be used when the returnAnimationFrameworkLibrary " +
+ check(returnAnimationFrameworkLongLived()) {
+ "Long-lived registrations cannot be used when the returnAnimationFrameworkLongLived " +
"flag is disabled"
}
diff --git a/packages/SystemUI/compose/core/TEST_MAPPING b/packages/SystemUI/compose/core/TEST_MAPPING
index b71c5fb..56e531d 100644
--- a/packages/SystemUI/compose/core/TEST_MAPPING
+++ b/packages/SystemUI/compose/core/TEST_MAPPING
@@ -1,26 +1,10 @@
{
"presubmit": [
{
- "name": "PlatformComposeCoreTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "PlatformComposeCoreTests"
},
{
- "name": "SystemUIComposeGalleryTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "SystemUIComposeGalleryTests"
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt b/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
index 4674d6e..c01396a 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
@@ -16,15 +16,16 @@
package com.android.compose.windowsizeclass
+import android.view.WindowManager
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
-import androidx.window.layout.WindowMetricsCalculator
val LocalWindowSizeClass =
staticCompositionLocalOf<WindowSizeClass> {
@@ -41,7 +42,10 @@
LocalConfiguration.current
val density = LocalDensity.current
val context = LocalContext.current
- val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context)
+ val metrics =
+ remember(context) {
+ context.getSystemService(WindowManager::class.java)!!.currentWindowMetrics
+ }
val size = with(density) { metrics.bounds.toComposeRect().size.toDpSize() }
return WindowSizeClass.calculateFromSize(size)
}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt
deleted file mode 100644
index c58df35..0000000
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/NotificationsShadeSceneModule.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2024 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.scene
-
-import com.android.systemui.notifications.ui.composable.NotificationsShadeScene
-import com.android.systemui.scene.ui.composable.Scene
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-
-@Module
-interface NotificationsShadeSceneModule {
-
- @Binds @IntoSet fun notificationsShade(scene: NotificationsShadeScene): Scene
-}
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
deleted file mode 100644
index 5bb6ae4..0000000
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2024 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.scene
-
-import com.android.systemui.qs.ui.composable.QuickSettingsShadeScene
-import com.android.systemui.scene.ui.composable.Scene
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-
-@Module
-interface QuickSettingsShadeSceneModule {
-
- @Binds @IntoSet fun quickSettingsShade(scene: QuickSettingsShadeScene): Scene
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index a4dc8fc..557257d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -72,7 +72,7 @@
override fun matches(key: ElementKey, content: ContentKey) = true
}
-private object TransitionDuration {
+object TransitionDuration {
const val BETWEEN_HUB_AND_EDIT_MODE_MS = 1000
const val EDIT_MODE_TO_HUB_CONTENT_MS = 167
const val EDIT_MODE_TO_HUB_GRID_DELAY_MS = 167
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index efe0f2e..f4d1242 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -108,6 +108,8 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
@@ -179,6 +181,7 @@
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@@ -1155,6 +1158,15 @@
val selectedIndex =
selectedKey?.let { key -> contentListState.list.indexOfFirst { it.key == key } }
+ val interactionSource = remember { MutableInteractionSource() }
+ val focusRequester = remember { FocusRequester() }
+ if (viewModel.isEditMode && selected) {
+ LaunchedEffect(Unit) {
+ delay(TransitionDuration.BETWEEN_HUB_AND_EDIT_MODE_MS.toLong())
+ focusRequester.requestFocus()
+ }
+ }
+
val isSelected = selectedKey == model.key
val selectableModifier =
@@ -1162,7 +1174,7 @@
Modifier.selectable(
selected = isSelected,
onClick = { viewModel.setSelectedKey(model.key) },
- interactionSource = remember { MutableInteractionSource() },
+ interactionSource = interactionSource,
indication = null,
)
} else {
@@ -1172,6 +1184,8 @@
Box(
modifier =
modifier
+ .focusRequester(focusRequester)
+ .focusable(interactionSource = interactionSource)
.then(selectableModifier)
.thenIf(!viewModel.isEditMode && !model.inQuietMode) {
Modifier.pointerInput(Unit) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
deleted file mode 100644
index 1f4cd04..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2024 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.notifications.ui.composable
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.UserAction
-import com.android.compose.animation.scene.UserActionResult
-import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeUserActionsViewModel
-import com.android.systemui.scene.session.ui.composable.SaveableSession
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.ui.composable.Scene
-import com.android.systemui.shade.shared.model.ShadeMode
-import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
-import com.android.systemui.shade.ui.composable.OverlayShade
-import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
-import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
-import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
-import com.android.systemui.statusbar.phone.ui.StatusBarIconController
-import com.android.systemui.statusbar.phone.ui.TintedIconManager
-import dagger.Lazy
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-@SysUISingleton
-class NotificationsShadeScene
-@Inject
-constructor(
- private val actionsViewModelFactory: NotificationsShadeUserActionsViewModel.Factory,
- private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
- private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
- private val tintedIconManagerFactory: TintedIconManager.Factory,
- private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
- private val statusBarIconController: StatusBarIconController,
- private val shadeSession: SaveableSession,
- private val stackScrollView: Lazy<NotificationScrollView>,
-) : ExclusiveActivatable(), Scene {
-
- override val key = Scenes.NotificationsShade
-
- private val actionsViewModel: NotificationsShadeUserActionsViewModel by lazy {
- actionsViewModelFactory.create()
- }
-
- override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
-
- override suspend fun onActivated(): Nothing {
- actionsViewModel.activate()
- }
-
- @Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
- val notificationsPlaceholderViewModel =
- rememberViewModel("NotificationsShadeScene") {
- notificationsPlaceholderViewModelFactory.create()
- }
-
- OverlayShade(
- modifier = modifier,
- onScrimClicked = {},
- ) {
- Column {
- ExpandedShadeHeader(
- viewModelFactory = shadeHeaderViewModelFactory,
- createTintedIconManager = tintedIconManagerFactory::create,
- createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
- statusBarIconController = statusBarIconController,
- modifier = Modifier.padding(horizontal = 16.dp),
- )
-
- NotificationScrollingStack(
- shadeSession = shadeSession,
- stackScrollView = stackScrollView.get(),
- viewModel = notificationsPlaceholderViewModel,
- maxScrimTop = { 0f },
- shouldPunchHoleBehindScrim = false,
- shouldFillMaxSize = false,
- shouldReserveSpaceForNavBar = false,
- shadeMode = ShadeMode.Dual,
- modifier = Modifier.fillMaxWidth(),
- )
-
- // Communicates the bottom position of the drawable area within the shade to NSSL.
- NotificationStackCutoffGuideline(
- stackScrollView = stackScrollView.get(),
- viewModel = notificationsPlaceholderViewModel,
- )
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index 671b012..a6d5c1c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -48,17 +48,13 @@
import com.android.systemui.scene.shared.model.Scenes
object QuickSettings {
- private val SCENES =
- setOf(
- Scenes.QuickSettings,
- Scenes.Shade,
- )
+ private val SCENES = setOf(Scenes.QuickSettings, Scenes.Shade)
object Elements {
val Content =
MovableElementKey(
"QuickSettingsContent",
- contentPicker = MovableElementContentPicker(SCENES)
+ contentPicker = MovableElementContentPicker(SCENES),
)
val QuickQuickSettings = ElementKey("QuickQuickSettings")
val SplitShadeQuickSettings = ElementKey("SplitShadeQuickSettings")
@@ -87,7 +83,7 @@
private fun SceneScope.stateForQuickSettingsContent(
isSplitShade: Boolean,
- squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default }
+ squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default },
): QSSceneAdapter.State {
return when (val transitionState = layoutState.transitionState) {
is TransitionState.Idle -> {
@@ -122,7 +118,7 @@
}
}
is TransitionState.Transition.OverlayTransition ->
- TODO("b/359173565: Handle overlay transitions")
+ error("Bad transition for QuickSettings scene: overlays not supported")
}
}
@@ -172,7 +168,7 @@
val height = heightProvider().coerceAtLeast(0)
layout(placeable.width, height) { placeable.placeRelative(0, 0) }
- }
+ },
) {
content { QuickSettingsContent(qsSceneAdapter = qsSceneAdapter, contentState) }
}
@@ -225,7 +221,7 @@
it.addView(view)
}
},
- onRelease = { it.removeAllViews() }
+ onRelease = { it.removeAllViews() },
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
deleted file mode 100644
index e27c7e2..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.ui.composable
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import com.android.compose.animation.scene.SceneScope
-import com.android.compose.animation.scene.UserAction
-import com.android.compose.animation.scene.UserActionResult
-import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneContentViewModel
-import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeUserActionsViewModel
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.scene.ui.composable.Scene
-import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
-import com.android.systemui.shade.ui.composable.OverlayShade
-import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
-import com.android.systemui.statusbar.phone.ui.StatusBarIconController
-import com.android.systemui.statusbar.phone.ui.TintedIconManager
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-
-@SysUISingleton
-class QuickSettingsShadeScene
-@Inject
-constructor(
- private val actionsViewModelFactory: QuickSettingsShadeUserActionsViewModel.Factory,
- private val contentViewModelFactory: QuickSettingsShadeSceneContentViewModel.Factory,
- private val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
- private val tintedIconManagerFactory: TintedIconManager.Factory,
- private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
- private val statusBarIconController: StatusBarIconController,
-) : ExclusiveActivatable(), Scene {
-
- override val key = Scenes.QuickSettingsShade
-
- private val actionsViewModel: QuickSettingsShadeUserActionsViewModel by lazy {
- actionsViewModelFactory.create()
- }
-
- override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
-
- override suspend fun onActivated(): Nothing {
- actionsViewModel.activate()
- }
-
- @Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) {
- val viewModel =
- rememberViewModel("QuickSettingsShadeScene") { contentViewModelFactory.create() }
-
- OverlayShade(
- modifier = modifier,
- onScrimClicked = {},
- ) {
- Column {
- ExpandedShadeHeader(
- viewModelFactory = shadeHeaderViewModelFactory,
- createTintedIconManager = tintedIconManagerFactory::create,
- createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
- statusBarIconController = statusBarIconController,
- modifier = Modifier.padding(QuickSettingsShade.Dimensions.Padding),
- )
-
- ShadeBody(
- viewModel = viewModel.quickSettingsContainerViewModel,
- )
- }
- }
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index f660808..f64d0ed 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -6,6 +6,7 @@
import com.android.compose.animation.scene.transitions
import com.android.systemui.bouncer.ui.composable.Bouncer
import com.android.systemui.notifications.ui.composable.Notifications
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
@@ -20,7 +21,11 @@
import com.android.systemui.scene.ui.composable.transitions.lockscreenToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToShadeTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToSplitShadeTransition
+import com.android.systemui.scene.ui.composable.transitions.notificationsShadeToQuickSettingsShadeTransition
import com.android.systemui.scene.ui.composable.transitions.shadeToQuickSettingsTransition
+import com.android.systemui.scene.ui.composable.transitions.toNotificationsShadeTransition
+import com.android.systemui.scene.ui.composable.transitions.toQuickSettingsShadeTransition
+import com.android.systemui.shade.ui.composable.OverlayShade
import com.android.systemui.shade.ui.composable.Shade
/**
@@ -74,6 +79,14 @@
from(Scenes.Lockscreen, to = Scenes.Gone) { lockscreenToGoneTransition() }
from(Scenes.Shade, to = Scenes.QuickSettings) { shadeToQuickSettingsTransition() }
+ // Overlay transitions
+
+ to(Overlays.NotificationsShade) { toNotificationsShadeTransition() }
+ to(Overlays.QuickSettingsShade) { toQuickSettingsShadeTransition() }
+ from(Overlays.NotificationsShade, Overlays.QuickSettingsShade) {
+ notificationsShadeToQuickSettingsShadeTransition()
+ }
+
// Scene overscroll
overscrollDisabled(Scenes.Gone, Orientation.Vertical)
@@ -91,4 +104,10 @@
y = Shade.Dimensions.ScrimOverscrollLimit,
)
}
+ overscroll(Overlays.NotificationsShade, Orientation.Vertical) {
+ translate(OverlayShade.Elements.Panel, y = OverlayShade.Dimensions.OverscrollLimit)
+ }
+ overscroll(Overlays.QuickSettingsShade, Orientation.Vertical) {
+ translate(OverlayShade.Elements.Panel, y = OverlayShade.Dimensions.OverscrollLimit)
+ }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
deleted file mode 100644
index 48ec198..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2024 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.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.goneToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale)
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsShadeTransition.kt
deleted file mode 100644
index 8a03e29..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsShadeTransition.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2024 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.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.Edge
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.goneToQuickSettingsShadeTransition(
- edge: Edge = Edge.Top,
- durationScale: Double = 1.0,
-) {
- toQuickSettingsShadeTransition(edge, durationScale)
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
deleted file mode 100644
index 02664c1..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2024 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.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.lockscreenToNotificationsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toNotificationsShadeTransition(durationScale = durationScale)
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsShadeTransition.kt
deleted file mode 100644
index 19aa3a7..0000000
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsShadeTransition.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2024 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.scene.ui.composable.transitions
-
-import com.android.compose.animation.scene.Edge
-import com.android.compose.animation.scene.TransitionBuilder
-
-fun TransitionBuilder.lockscreenToQuickSettingsShadeTransition(
- durationScale: Double = 1.0,
-) {
- toQuickSettingsShadeTransition(Edge.Top, durationScale)
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromNotificationsShadeToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromNotificationsShadeToQuickSettingsShadeTransition.kt
new file mode 100644
index 0000000..24f285e
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromNotificationsShadeToQuickSettingsShadeTransition.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.scene.ui.composable.transitions
+
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.tween
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.shade.ui.composable.Shade
+import kotlin.time.Duration.Companion.milliseconds
+
+fun TransitionBuilder.notificationsShadeToQuickSettingsShadeTransition(
+ durationScale: Double = 1.0
+) {
+ spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
+ swipeSpec =
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
+ )
+}
+
+private val DefaultDuration = 300.milliseconds
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
index 9d13647..55fa6ad 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
@@ -26,10 +26,7 @@
import com.android.systemui.shade.ui.composable.Shade
import kotlin.time.Duration.Companion.milliseconds
-fun TransitionBuilder.toQuickSettingsShadeTransition(
- edge: Edge = Edge.Top,
- durationScale: Double = 1.0,
-) {
+fun TransitionBuilder.toQuickSettingsShadeTransition(durationScale: Double = 1.0) {
spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
swipeSpec =
spring(
@@ -38,7 +35,7 @@
)
distance = UserActionDistance { fromSceneSize, _ -> fromSceneSize.height.toFloat() * 2 / 3f }
- translate(OverlayShade.Elements.Panel, edge)
+ translate(OverlayShade.Elements.Panel, Edge.Top)
fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 8922224..6c4edf4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -18,6 +18,7 @@
package com.android.systemui.shade.ui.composable
+import android.view.HapticFeedbackConstants
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
@@ -39,17 +40,20 @@
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.LowestZIndexContentPicker
import com.android.compose.animation.scene.SceneScope
import com.android.compose.windowsizeclass.LocalWindowSizeClass
+import com.android.systemui.scene.shared.model.Scenes
/** Renders a lightweight shade UI container, as an overlay. */
@Composable
@@ -58,26 +62,27 @@
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
+ val view = LocalView.current
+ LaunchedEffect(Unit) {
+ if (layoutState.currentTransition?.fromContent == Scenes.Gone) {
+ view.performHapticFeedback(HapticFeedbackConstants.GESTURE_START)
+ }
+ }
+
Box(modifier) {
Scrim(onClicked = onScrimClicked)
- Box(
- modifier = Modifier.fillMaxSize().panelPadding(),
- contentAlignment = Alignment.TopEnd,
- ) {
+ Box(modifier = Modifier.fillMaxSize().panelPadding(), contentAlignment = Alignment.TopEnd) {
Panel(
modifier = Modifier.element(OverlayShade.Elements.Panel).panelSize(),
- content = content
+ content = content,
)
}
}
}
@Composable
-private fun SceneScope.Scrim(
- onClicked: () -> Unit,
- modifier: Modifier = Modifier,
-) {
+private fun SceneScope.Scrim(onClicked: () -> Unit, modifier: Modifier = Modifier) {
Spacer(
modifier =
modifier
@@ -89,10 +94,7 @@
}
@Composable
-private fun SceneScope.Panel(
- modifier: Modifier = Modifier,
- content: @Composable () -> Unit,
-) {
+private fun SceneScope.Panel(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
Box(modifier = modifier.clip(OverlayShade.Shapes.RoundedCornerPanel)) {
Spacer(
modifier =
@@ -101,7 +103,7 @@
.background(
color = OverlayShade.Colors.PanelBackground,
shape = OverlayShade.Shapes.RoundedCornerPanel,
- ),
+ )
)
// This content is intentionally rendered as a separate element from the background in order
@@ -137,7 +139,7 @@
systemBars.asPaddingValues(),
displayCutout.asPaddingValues(),
waterfall.asPaddingValues(),
- contentPadding
+ contentPadding,
)
return if (widthSizeClass == WindowWidthSizeClass.Compact) {
@@ -156,14 +158,19 @@
start = paddingValues.maxOfOrNull { it.calculateStartPadding(layoutDirection) } ?: 0.dp,
top = paddingValues.maxOfOrNull { it.calculateTopPadding() } ?: 0.dp,
end = paddingValues.maxOfOrNull { it.calculateEndPadding(layoutDirection) } ?: 0.dp,
- bottom = paddingValues.maxOfOrNull { it.calculateBottomPadding() } ?: 0.dp
+ bottom = paddingValues.maxOfOrNull { it.calculateBottomPadding() } ?: 0.dp,
)
}
object OverlayShade {
object Elements {
val Scrim = ElementKey("OverlayShadeScrim", contentPicker = LowestZIndexContentPicker)
- val Panel = ElementKey("OverlayShadePanel", contentPicker = LowestZIndexContentPicker)
+ val Panel =
+ ElementKey(
+ "OverlayShadePanel",
+ contentPicker = LowestZIndexContentPicker,
+ placeAllCopies = true,
+ )
val PanelBackground =
ElementKey("OverlayShadePanelBackground", contentPicker = LowestZIndexContentPicker)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index df22264..8a59e20 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade.ui.composable
+import android.view.HapticFeedbackConstants
import android.view.ViewGroup
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
@@ -60,6 +61,7 @@
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
@@ -178,9 +180,7 @@
override val userActions: Flow<Map<UserAction, UserActionResult>> = actionsViewModel.actions
@Composable
- override fun SceneScope.Content(
- modifier: Modifier,
- ) =
+ override fun SceneScope.Content(modifier: Modifier) =
ShadeScene(
notificationStackScrollView.get(),
viewModel =
@@ -224,6 +224,13 @@
modifier: Modifier = Modifier,
shadeSession: SaveableSession,
) {
+ val view = LocalView.current
+ LaunchedEffect(Unit) {
+ if (layoutState.currentTransition?.fromContent == Scenes.Gone) {
+ view.performHapticFeedback(HapticFeedbackConstants.GESTURE_START)
+ }
+ }
+
val shadeMode by viewModel.shadeMode.collectAsStateWithLifecycle()
when (shadeMode) {
is ShadeMode.Single ->
@@ -282,7 +289,7 @@
animateSceneFloatAsState(
value = 1f,
key = QuickSettings.SharedValues.TilesSquishiness,
- canOverflow = false
+ canOverflow = false,
)
val isEmptySpaceClickable by viewModel.isEmptySpaceClickable.collectAsStateWithLifecycle()
val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle()
@@ -320,7 +327,7 @@
} else {
cutoutInsets
}
- }
+ },
)
}
@@ -337,7 +344,7 @@
modifier =
Modifier.fillMaxSize()
.element(Shade.Elements.BackgroundScrim)
- .background(colorResource(R.color.shade_scrim_background_dark)),
+ .background(colorResource(R.color.shade_scrim_background_dark))
)
Layout(
modifier =
@@ -398,13 +405,13 @@
.pointerInteropFilter { true }
.verticalNestedScrollToScene(
topBehavior = NestedScrollBehavior.EdgeAlways,
- isExternalOverscrollGesture = { false }
+ isExternalOverscrollGesture = { false },
)
) {
NotificationStackCutoffGuideline(
stackScrollView = notificationStackScrollView,
viewModel = notificationsPlaceholderViewModel,
- modifier = Modifier.align(Alignment.TopCenter)
+ modifier = Modifier.align(Alignment.TopCenter),
)
}
}
@@ -440,24 +447,16 @@
canOverflow = false,
)
val unfoldTranslationXForStartSide by
- viewModel
- .unfoldTranslationX(
- isOnStartSide = true,
- )
- .collectAsStateWithLifecycle(0f)
+ viewModel.unfoldTranslationX(isOnStartSide = true).collectAsStateWithLifecycle(0f)
val unfoldTranslationXForEndSide by
- viewModel
- .unfoldTranslationX(
- isOnStartSide = false,
- )
- .collectAsStateWithLifecycle(0f)
+ viewModel.unfoldTranslationX(isOnStartSide = false).collectAsStateWithLifecycle(0f)
val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
val bottomPadding by
animateDpAsState(
targetValue = if (isCustomizing) 0.dp else navBarBottomHeight,
animationSpec = tween(customizingAnimationDuration),
- label = "animateQSSceneBottomPaddingAsState"
+ label = "animateQSSceneBottomPaddingAsState",
)
val density = LocalDensity.current
LaunchedEffect(navBarBottomHeight, density) {
@@ -516,9 +515,7 @@
)
)
- Column(
- modifier = Modifier.fillMaxSize(),
- ) {
+ Column(modifier = Modifier.fillMaxSize()) {
CollapsedShadeHeader(
viewModelFactory = viewModel.shadeHeaderViewModelFactory,
createTintedIconManager = createTintedIconManager,
@@ -526,9 +523,7 @@
statusBarIconController = statusBarIconController,
modifier =
Modifier.then(brightnessMirrorShowingModifier)
- .padding(
- horizontal = { unfoldTranslationXForStartSide.roundToInt() },
- )
+ .padding(horizontal = { unfoldTranslationXForStartSide.roundToInt() }),
)
Row(modifier = Modifier.fillMaxWidth().weight(1f)) {
@@ -536,14 +531,14 @@
modifier =
Modifier.element(Shade.Elements.SplitShadeStartColumn)
.weight(1f)
- .graphicsLayer { translationX = unfoldTranslationXForStartSide },
+ .graphicsLayer { translationX = unfoldTranslationXForStartSide }
) {
BrightnessMirror(
viewModel = brightnessMirrorViewModel,
qsSceneAdapter = viewModel.qsSceneAdapter,
// Need to use the offset measured from the container as the header
// has to be accounted for
- measureFromContainer = true
+ measureFromContainer = true,
)
Column(
verticalArrangement = Arrangement.Top,
@@ -557,7 +552,7 @@
.thenIf(!isCustomizerShowing) {
Modifier.verticalScroll(
quickSettingsScrollState,
- enabled = isScrollable
+ enabled = isScrollable,
)
.clipScrollableContainer(Orientation.Horizontal)
}
@@ -619,16 +614,16 @@
.padding(
end =
dimensionResource(R.dimen.notification_panel_margin_horizontal),
- bottom = navBarBottomHeight
+ bottom = navBarBottomHeight,
)
- .then(brightnessMirrorShowingModifier)
+ .then(brightnessMirrorShowingModifier),
)
}
}
NotificationStackCutoffGuideline(
stackScrollView = notificationStackScrollView,
viewModel = notificationsPlaceholderViewModel,
- modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding()
+ modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding(),
)
}
}
@@ -652,6 +647,6 @@
null
} else {
{ mediaOffsetProvider.offset }
- }
+ },
)
}
diff --git a/packages/SystemUI/compose/scene/TEST_MAPPING b/packages/SystemUI/compose/scene/TEST_MAPPING
index f9424ed..65ba037 100644
--- a/packages/SystemUI/compose/scene/TEST_MAPPING
+++ b/packages/SystemUI/compose/scene/TEST_MAPPING
@@ -1,37 +1,13 @@
{
"presubmit": [
{
- "name": "PlatformComposeSceneTransitionLayoutTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "PlatformComposeSceneTransitionLayoutTests"
},
{
- "name": "PlatformComposeCoreTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "PlatformComposeCoreTests"
},
{
- "name": "SystemUIComposeGalleryTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "SystemUIComposeGalleryTests"
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index fb9dde3..0bb1d92 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -51,6 +51,7 @@
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastAny
+import androidx.compose.ui.util.fastFilter
import androidx.compose.ui.util.fastFirstOrNull
import androidx.compose.ui.util.fastSumBy
import com.android.compose.ui.util.SpaceVectorConverter
@@ -234,8 +235,15 @@
pointersDown == 0 -> {
startedPosition = null
- val lastPointerUp = changes.single { it.id == velocityPointerId }
- velocityTracker.addPointerInputChange(lastPointerUp)
+ // In case of multiple events with 0 pointers down (not pressed) we may have
+ // already removed the velocityPointer
+ val lastPointerUp = changes.fastFilter { it.id == velocityPointerId }
+ check(lastPointerUp.isEmpty() || lastPointerUp.size == 1) {
+ "There are ${lastPointerUp.size} pointers up: $lastPointerUp"
+ }
+ if (lastPointerUp.size == 1) {
+ velocityTracker.addPointerInputChange(lastPointerUp.first())
+ }
}
// The first pointer down, startedPosition was not set.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index f20548b..cec8883 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -100,6 +100,10 @@
* By default overlays are centered in their layout but they can be aligned differently using
* [alignment].
*
+ * If [isModal] is true (the default), then a protective layer will be added behind the overlay
+ * to prevent swipes from reaching other scenes or overlays behind this one. Clicking this
+ * protective layer will close the overlay.
+ *
* Important: overlays must be defined after all scenes. Overlay order along the z-axis follows
* call order. Calling overlay(A) followed by overlay(B) will mean that overlay B renders
* after/above overlay A.
@@ -109,6 +113,7 @@
userActions: Map<UserAction, UserActionResult> =
mapOf(Back to UserActionResult.HideOverlay(key)),
alignment: Alignment = Alignment.Center,
+ isModal: Boolean = true,
content: @Composable ContentScope.() -> Unit,
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index fe05234..65c4043 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -17,12 +17,16 @@
package com.android.compose.animation.scene
import androidx.annotation.VisibleForTesting
+import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.key
+import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
@@ -253,6 +257,7 @@
key: OverlayKey,
userActions: Map<UserAction, UserActionResult>,
alignment: Alignment,
+ isModal: Boolean,
content: @Composable (ContentScope.() -> Unit),
) {
overlaysDefined = true
@@ -266,6 +271,7 @@
overlay.zIndex = zIndex
overlay.userActions = resolvedUserActions
overlay.alignment = alignment
+ overlay.isModal = isModal
} else {
// New overlay.
overlays[key] =
@@ -276,6 +282,7 @@
resolvedUserActions,
zIndex,
alignment,
+ isModal,
)
}
@@ -399,12 +406,30 @@
return
}
- // We put the overlays inside a Box that is matching the layout size so that overlays are
- // measured after all scenes and that their max size is the size of the layout without the
- // overlays.
- Box(Modifier.matchParentSize().zIndex(overlaysOrderedByZIndex.first().zIndex)) {
- overlaysOrderedByZIndex.fastForEach { overlay ->
- key(overlay.key) { overlay.Content(Modifier.align(overlay.alignment)) }
+ overlaysOrderedByZIndex.fastForEach { overlay ->
+ val key = overlay.key
+ key(key) {
+ // We put the overlays inside a Box that is matching the layout size so that they
+ // are measured after all scenes and that their max size is the size of the layout
+ // without the overlays.
+ Box(Modifier.matchParentSize().zIndex(overlay.zIndex)) {
+ if (overlay.isModal) {
+ // Add a fullscreen clickable to prevent swipes from reaching the scenes and
+ // other overlays behind this overlay. Clicking will close the overlay.
+ Box(
+ Modifier.fillMaxSize().clickable(
+ interactionSource = remember { MutableInteractionSource() },
+ indication = null,
+ ) {
+ if (state.canHideOverlay(key)) {
+ state.hideOverlay(key, animationScope = animationScope)
+ }
+ }
+ )
+ }
+
+ overlay.Content(Modifier.align(overlay.alignment))
+ }
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt
index ccec9e8..d4de559 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt
@@ -37,8 +37,10 @@
actions: Map<UserAction.Resolved, UserActionResult>,
zIndex: Float,
alignment: Alignment,
+ isModal: Boolean,
) : Content(key, layoutImpl, content, actions, zIndex) {
var alignment by mutableStateOf(alignment)
+ var isModal by mutableStateOf(isModal)
override fun toString(): String {
return "Overlay(key=$key)"
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
index ffed15b..cae6617 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt
@@ -18,10 +18,12 @@
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -31,19 +33,26 @@
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.click
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipe
+import androidx.compose.ui.test.swipeUp
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.TestOverlays.OverlayA
import com.android.compose.animation.scene.TestOverlays.OverlayB
import com.android.compose.animation.scene.TestScenes.SceneA
+import com.android.compose.animation.scene.subjects.assertThat
import com.android.compose.test.assertSizeIsEqualTo
import com.android.compose.test.setContentAndCreateMainScope
import com.android.compose.test.subjects.assertThat
@@ -769,4 +778,59 @@
.assertSizeIsEqualTo(100.dp)
.assertIsDisplayed()
}
+
+ @Test
+ fun overlaysAreModalByDefault() {
+ val state = rule.runOnUiThread { MutableSceneTransitionLayoutStateImpl(SceneA) }
+
+ val scrollState = ScrollState(initial = 0)
+ val scope =
+ rule.setContentAndCreateMainScope {
+ SceneTransitionLayout(state) {
+ // Make the scene vertically scrollable.
+ scene(SceneA) {
+ Box(Modifier.size(200.dp).verticalScroll(scrollState)) {
+ Box(Modifier.size(200.dp, 400.dp))
+ }
+ }
+
+ // The overlay is at the center end of the scene.
+ overlay(OverlayA, alignment = Alignment.CenterEnd) {
+ Box(Modifier.size(100.dp))
+ }
+ }
+ }
+
+ fun swipeUp() {
+ rule.onRoot().performTouchInput {
+ swipe(start = Offset(x = 0f, y = bottom), end = Offset(x = 0f, y = top))
+ }
+ }
+
+ // Swiping up on the scene scrolls the list.
+ assertThat(scrollState.value).isEqualTo(0)
+ swipeUp()
+ assertThat(scrollState.value).isNotEqualTo(0)
+
+ // Reset the scroll.
+ scope.launch { scrollState.scrollTo(0) }
+ rule.waitForIdle()
+ assertThat(scrollState.value).isEqualTo(0)
+
+ // Show the overlay.
+ rule.runOnUiThread { state.showOverlay(OverlayA, animationScope = scope) }
+ rule.waitForIdle()
+ assertThat(state.transitionState).isIdle()
+ assertThat(state.transitionState).hasCurrentOverlays(OverlayA)
+
+ // Swiping up does not scroll the scene behind the overlay.
+ swipeUp()
+ assertThat(scrollState.value).isEqualTo(0)
+
+ // Clicking outside the overlay will close it.
+ rule.onRoot().performTouchInput { click(Offset.Zero) }
+ rule.waitForIdle()
+ assertThat(state.transitionState).isIdle()
+ assertThat(state.transitionState).hasCurrentOverlays(/* empty */ )
+ }
}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 502dbe3..5ed11ad 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -34,6 +34,7 @@
import com.android.systemui.plugins.clocks.ClockFaceController
import com.android.systemui.plugins.clocks.ClockFaceEvents
import com.android.systemui.plugins.clocks.ClockMessageBuffers
+import com.android.systemui.plugins.clocks.ClockReactiveSetting
import com.android.systemui.plugins.clocks.ClockSettings
import com.android.systemui.plugins.clocks.DefaultClockFaceLayout
import com.android.systemui.plugins.clocks.WeatherData
@@ -73,7 +74,7 @@
ClockConfig(
DEFAULT_CLOCK_ID,
resources.getString(R.string.clock_default_name),
- resources.getString(R.string.clock_default_description)
+ resources.getString(R.string.clock_default_description),
)
}
@@ -84,14 +85,14 @@
layoutInflater.inflate(R.layout.clock_default_small, parent, false)
as AnimatableClockView,
settings?.seedColor,
- messageBuffers?.smallClockMessageBuffer
+ messageBuffers?.smallClockMessageBuffer,
)
largeClock =
LargeClockFaceController(
layoutInflater.inflate(R.layout.clock_default_large, parent, false)
as AnimatableClockView,
settings?.seedColor,
- messageBuffers?.largeClockMessageBuffer
+ messageBuffers?.largeClockMessageBuffer,
)
clocks = listOf(smallClock.view, largeClock.view)
@@ -272,8 +273,12 @@
}
override fun onWeatherDataChanged(data: WeatherData) {}
+
override fun onAlarmDataChanged(data: AlarmData) {}
+
override fun onZenDataChanged(data: ZenData) {}
+
+ override fun onReactiveAxesChanged(axes: List<ClockReactiveSetting>) {}
}
open inner class DefaultClockAnimations(
@@ -340,10 +345,9 @@
}
}
- class AnimationState(
- var fraction: Float,
- ) {
+ class AnimationState(var fraction: Float) {
var isActive: Boolean = fraction > 0.5f
+
fun update(newFraction: Float): Pair<Boolean, Boolean> {
if (newFraction == fraction) {
return Pair(isActive, false)
diff --git a/packages/SystemUI/docs/scene.md b/packages/SystemUI/docs/scene.md
index 0ac15c5..234c7a0 100644
--- a/packages/SystemUI/docs/scene.md
+++ b/packages/SystemUI/docs/scene.md
@@ -68,15 +68,13 @@
1. Set a collection of **aconfig flags** to `true` by running the following
commands:
```console
- $ adb shell device_config override systemui com.android.systemui.scene_container true
- $ adb shell device_config override systemui com.android.systemui.compose_lockscreen true
$ adb shell device_config override systemui com.android.systemui.keyguard_bottom_area_refactor true
$ adb shell device_config override systemui com.android.systemui.keyguard_wm_state_refactor true
- $ adb shell device_config override systemui com.android.systemui.media_in_scene_container true
$ adb shell device_config override systemui com.android.systemui.migrate_clocks_to_blueprint true
- $ adb shell device_config override systemui com.android.systemui.notifications_heads_up_refactor true
+ $ adb shell device_config override systemui com.android.systemui.notification_avalanche_throttle_hun true
$ adb shell device_config override systemui com.android.systemui.predictive_back_sysui true
$ adb shell device_config override systemui com.android.systemui.device_entry_udfps_refactor true
+ $ adb shell device_config override systemui com.android.systemui.scene_container true
```
2. **Restart** System UI by issuing the following command:
```console
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 156e068..312e62d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -196,6 +196,28 @@
}
@Test
+ public void testUserSwitcherToOneHandedRemovesViews() {
+ // Can happen when a SIM is inserted into a large screen device
+ initMode(MODE_USER_SWITCHER);
+ {
+ View view1 = mKeyguardSecurityContainer.findViewById(
+ R.id.keyguard_bouncer_user_switcher);
+ View view2 = mKeyguardSecurityContainer.findViewById(R.id.user_switcher_header);
+ assertThat(view1).isNotNull();
+ assertThat(view2).isNotNull();
+ }
+
+ initMode(MODE_ONE_HANDED);
+ {
+ View view1 = mKeyguardSecurityContainer.findViewById(
+ R.id.keyguard_bouncer_user_switcher);
+ View view2 = mKeyguardSecurityContainer.findViewById(R.id.user_switcher_header);
+ assertThat(view1).isNull();
+ assertThat(view2).isNull();
+ }
+ }
+
+ @Test
public void updatePosition_movesKeyguard() {
setupForUpdateKeyguardPosition(/* oneHandedMode= */ true);
mKeyguardSecurityContainer.updatePositionByTouchX(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 75ae414..b96e40f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -244,10 +244,7 @@
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
// Widgets available.
@@ -267,21 +264,14 @@
fun smartspaceDynamicSizing_oneCard_fullSize() =
testSmartspaceDynamicSizing(
totalTargets = 1,
- expectedSizes =
- listOf(
- CommunalContentSize.FULL,
- )
+ expectedSizes = listOf(CommunalContentSize.FULL),
)
@Test
fun smartspace_dynamicSizing_twoCards_halfSize() =
testSmartspaceDynamicSizing(
totalTargets = 2,
- expectedSizes =
- listOf(
- CommunalContentSize.HALF,
- CommunalContentSize.HALF,
- )
+ expectedSizes = listOf(CommunalContentSize.HALF, CommunalContentSize.HALF),
)
@Test
@@ -293,34 +283,34 @@
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
- )
+ ),
)
@Test
- fun smartspace_dynamicSizing_fourCards_oneFullAndThreeThirdSize() =
+ fun smartspace_dynamicSizing_fourCards_threeThirdSizeAndOneFullSize() =
testSmartspaceDynamicSizing(
totalTargets = 4,
expectedSizes =
listOf(
+ CommunalContentSize.THIRD,
+ CommunalContentSize.THIRD,
+ CommunalContentSize.THIRD,
CommunalContentSize.FULL,
- CommunalContentSize.THIRD,
- CommunalContentSize.THIRD,
- CommunalContentSize.THIRD,
- )
+ ),
)
@Test
- fun smartspace_dynamicSizing_fiveCards_twoHalfAndThreeThirdSize() =
+ fun smartspace_dynamicSizing_fiveCards_threeThirdAndTwoHalfSize() =
testSmartspaceDynamicSizing(
totalTargets = 5,
expectedSizes =
listOf(
+ CommunalContentSize.THIRD,
+ CommunalContentSize.THIRD,
+ CommunalContentSize.THIRD,
CommunalContentSize.HALF,
CommunalContentSize.HALF,
- CommunalContentSize.THIRD,
- CommunalContentSize.THIRD,
- CommunalContentSize.THIRD,
- )
+ ),
)
@Test
@@ -335,7 +325,7 @@
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
CommunalContentSize.THIRD,
- )
+ ),
)
private fun testSmartspaceDynamicSizing(
@@ -355,7 +345,7 @@
smartspaceRepository.setTimers(targets)
- val smartspaceContent by collectLastValue(underTest.ongoingContent)
+ val smartspaceContent by collectLastValue(underTest.ongoingContent(false))
assertThat(smartspaceContent?.size).isEqualTo(totalTargets)
for (index in 0 until totalTargets) {
assertThat(smartspaceContent?.get(index)?.size).isEqualTo(expectedSizes[index])
@@ -371,7 +361,7 @@
// Media is playing.
mediaRepository.mediaActive()
- val umoContent by collectLastValue(underTest.ongoingContent)
+ val umoContent by collectLastValue(underTest.ongoingContent(true))
assertThat(umoContent?.size).isEqualTo(1)
assertThat(umoContent?.get(0)).isInstanceOf(CommunalContentModel.Umo::class.java)
@@ -379,6 +369,19 @@
}
@Test
+ fun umo_mediaPlaying_mediaHostNotVisible_hidesUmo() =
+ testScope.runTest {
+ // Tutorial completed.
+ tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+
+ // Media is playing.
+ mediaRepository.mediaActive()
+
+ val umoContent by collectLastValue(underTest.ongoingContent(false))
+ assertThat(umoContent?.size).isEqualTo(0)
+ }
+
+ @Test
fun ongoing_shouldOrderAndSizeByTimestamp() =
testScope.runTest {
// Keyguard showing, and tutorial completed.
@@ -401,19 +404,19 @@
val timer3 = smartspaceTimer("timer3", timestamp = 4L)
smartspaceRepository.setTimers(listOf(timer1, timer2, timer3))
- val ongoingContent by collectLastValue(underTest.ongoingContent)
+ val ongoingContent by collectLastValue(underTest.ongoingContent(true))
assertThat(ongoingContent?.size).isEqualTo(4)
assertThat(ongoingContent?.get(0)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer3"))
- assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.FULL)
+ assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(1)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer2"))
- assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(2)?.key).isEqualTo(CommunalContentModel.KEY.umo())
- assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.HALF)
assertThat(ongoingContent?.get(3)?.key)
.isEqualTo(CommunalContentModel.KEY.smartspace("timer1"))
- assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.THIRD)
+ assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.HALF)
}
@Test
@@ -435,10 +438,7 @@
testScope.runTest {
// Set to main user, so we can dismiss the tile for the main user.
val user = userRepository.asMainUser()
- userTracker.set(
- userInfos = listOf(user),
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = listOf(user), selectedUserIndex = 0)
runCurrent()
tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
@@ -816,10 +816,7 @@
// Only main user exists.
val userInfos = listOf(MAIN_USER_INFO)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
val widgetContent by collectLastValue(underTest.widgetContent)
@@ -853,10 +850,7 @@
// Work profile is set up.
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
runCurrent()
// When work profile is paused.
@@ -899,10 +893,7 @@
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
userRepository.setSelectedUserInfo(MAIN_USER_INFO)
runCurrent()
@@ -914,7 +905,7 @@
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
- DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL
+ DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL,
)
// Widgets under work profile are filtered out. Only the regular widget remains.
@@ -932,10 +923,7 @@
val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
userRepository.setUserInfos(userInfos)
- userTracker.set(
- userInfos = userInfos,
- selectedUserIndex = 0,
- )
+ userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
userRepository.setSelectedUserInfo(MAIN_USER_INFO)
runCurrent()
@@ -947,7 +935,7 @@
setKeyguardFeaturesDisabled(
USER_INFO_WORK,
- DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE
+ DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE,
)
// Widgets under work profile are available.
@@ -967,7 +955,7 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -983,7 +971,7 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isFalse()
@@ -999,7 +987,7 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
runCurrent()
kosmos.setCommunalAvailable(false)
@@ -1017,13 +1005,13 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.GLANCEABLE_HUB,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
runCurrent()
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.OCCLUDED,
to = KeyguardState.PRIMARY_BOUNCER,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -1039,7 +1027,7 @@
kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.DREAMING,
to = KeyguardState.OCCLUDED,
- testScope
+ testScope,
)
assertThat(showCommunalFromOccluded).isTrue()
@@ -1049,7 +1037,7 @@
return CommunalSmartspaceTimer(
smartspaceTargetId = id,
createdTimestampMillis = timestamp,
- remoteViews = mock(RemoteViews::class.java)
+ remoteViews = mock(RemoteViews::class.java),
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 780d357..09daa51 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -43,6 +43,7 @@
import com.android.systemui.communal.domain.interactor.communalTutorialInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.log.CommunalMetricsLogger
+import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS
@@ -150,10 +151,7 @@
kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
- kosmos.fakeUserTracker.set(
- userInfos = listOf(MAIN_USER_INFO),
- selectedUserIndex = 0,
- )
+ kosmos.fakeUserTracker.set(userInfos = listOf(MAIN_USER_INFO), selectedUserIndex = 0)
whenever(mediaHost.visible).thenReturn(true)
kosmos.powerInteractor.setAwakeForTest()
@@ -249,6 +247,87 @@
}
@Test
+ fun ongoingContent_umoAndOneTimer_sizedAppropriately() =
+ testScope.runTest {
+ // Widgets available.
+ widgetRepository.addWidget(appWidgetId = 0, rank = 30)
+ widgetRepository.addWidget(appWidgetId = 1, rank = 20)
+
+ // Smartspace available.
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ )
+ )
+ )
+
+ // Media playing.
+ mediaRepository.mediaActive()
+
+ val communalContent by collectLastValue(underTest.communalContent)
+
+ // One timer, UMO, two widgets, and cta.
+ assertThat(communalContent?.size).isEqualTo(5)
+
+ val timer = communalContent?.get(0)
+ val umo = communalContent?.get(1)
+
+ assertThat(timer).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(umo).isInstanceOf(CommunalContentModel.Umo::class.java)
+
+ assertThat(timer?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(umo?.size).isEqualTo(CommunalContentSize.HALF)
+ }
+
+ @Test
+ fun ongoingContent_umoAndTwoTimers_sizedAppropriately() =
+ testScope.runTest {
+ // Widgets available.
+ widgetRepository.addWidget(appWidgetId = 0, rank = 30)
+ widgetRepository.addWidget(appWidgetId = 1, rank = 20)
+
+ // Smartspace available.
+ smartspaceRepository.setTimers(
+ listOf(
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ ),
+ CommunalSmartspaceTimer(
+ smartspaceTargetId = "target",
+ createdTimestampMillis = 0L,
+ remoteViews = Mockito.mock(RemoteViews::class.java),
+ ),
+ )
+ )
+
+ // Media playing.
+ mediaRepository.mediaActive()
+
+ val communalContent by collectLastValue(underTest.communalContent)
+
+ // Two timers, UMO, two widgets, and cta.
+ assertThat(communalContent?.size).isEqualTo(6)
+
+ val timer1 = communalContent?.get(0)
+ val timer2 = communalContent?.get(1)
+ val umo = communalContent?.get(2)
+
+ assertThat(timer1).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(timer2).isInstanceOf(CommunalContentModel.Smartspace::class.java)
+ assertThat(umo).isInstanceOf(CommunalContentModel.Umo::class.java)
+
+ // One full-sized timer and a half-sized timer and half-sized UMO.
+ assertThat(timer1?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(timer2?.size).isEqualTo(CommunalContentSize.HALF)
+ assertThat(umo?.size).isEqualTo(CommunalContentSize.FULL)
+ }
+
+ @Test
fun communalContent_mediaHostVisible_umoIncluded() =
testScope.runTest {
// Media playing.
@@ -497,7 +576,7 @@
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GLANCEABLE_HUB,
- )
+ ),
)
// Shade not expanded.
if (!SceneContainerFlag.isEnabled) shadeTestUtil.setLockscreenShadeExpansion(0f)
@@ -550,8 +629,8 @@
stateTransition =
TransitionStep(
from = KeyguardState.DREAMING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ to = KeyguardState.GLANCEABLE_HUB
+ ),
)
// Then flow is not frozen
@@ -570,8 +649,8 @@
stateTransition =
TransitionStep(
from = KeyguardState.GLANCEABLE_HUB,
- to = KeyguardState.OCCLUDED,
- )
+ to = KeyguardState.OCCLUDED
+ ),
)
// Then flow is not frozen
@@ -595,7 +674,7 @@
TransitionStep(
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.GLANCEABLE_HUB,
- )
+ ),
)
// Then flow is not frozen
@@ -614,7 +693,7 @@
to = KeyguardState.OCCLUDED,
transitionState = TransitionState.STARTED,
value = 0f,
- )
+ ),
)
// Then flow is frozen
@@ -629,7 +708,7 @@
to = KeyguardState.OCCLUDED,
transitionState = TransitionState.FINISHED,
value = 1f,
- )
+ ),
)
// Then flow is not frozen
@@ -658,8 +737,8 @@
stateTransition =
TransitionStep(
from = KeyguardState.DREAMING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
+ to = KeyguardState.GLANCEABLE_HUB
+ ),
)
// Widgets available
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt
index 50b727c..9cfd328 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.education.data.model.EduDeviceConnectionTime
import com.android.systemui.education.data.model.GestureEduModel
+import com.android.systemui.education.domain.interactor.mockEduInputManager
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -62,7 +63,13 @@
// Create TestContext here because TemporaryFolder.create() is called in @Before. It is
// needed before calling TemporaryFolder.newFolder().
val testContext = TestContext(context, tmpFolder.newFolder())
- underTest = UserContextualEducationRepository(testContext, dsScopeProvider)
+ underTest =
+ UserContextualEducationRepository(
+ testContext,
+ dsScopeProvider,
+ kosmos.mockEduInputManager,
+ kosmos.testDispatcher
+ )
underTest.setUser(testUserId)
}
@@ -99,7 +106,8 @@
lastShortcutTriggeredTime = kosmos.fakeEduClock.instant(),
lastEducationTime = kosmos.fakeEduClock.instant(),
usageSessionStartTime = kosmos.fakeEduClock.instant(),
- userId = testUserId
+ userId = testUserId,
+ gestureType = BACK
)
underTest.updateGestureEduModel(BACK) { newModel }
val model by collectLastValue(underTest.readGestureEduModelFlow(BACK))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
index 64915fb..8201bbe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt
@@ -17,15 +17,13 @@
package com.android.systemui.education.domain.interactor
import android.content.pm.UserInfo
-import android.hardware.input.InputManager
-import android.hardware.input.KeyGestureEvent
-import android.view.KeyEvent
-import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.contextualeducation.GestureType
import com.android.systemui.contextualeducation.GestureType.ALL_APPS
import com.android.systemui.contextualeducation.GestureType.BACK
+import com.android.systemui.contextualeducation.GestureType.HOME
+import com.android.systemui.contextualeducation.GestureType.OVERVIEW
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.education.data.model.GestureEduModel
@@ -40,20 +38,21 @@
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.kotlin.any
-import org.mockito.kotlin.verify
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(ParameterizedAndroidJunit4::class)
@kotlinx.coroutines.ExperimentalCoroutinesApi
-class KeyboardTouchpadEduInteractorTest : SysuiTestCase() {
+class KeyboardTouchpadEduInteractorTest(private val gestureType: GestureType) : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val contextualEduInteractor = kosmos.contextualEducationInteractor
@@ -71,21 +70,27 @@
underTest.start()
contextualEduInteractor.start()
userRepository.setUserInfos(USER_INFOS)
+ testScope.launch {
+ contextualEduInteractor.updateKeyboardFirstConnectionTime()
+ contextualEduInteractor.updateTouchpadFirstConnectionTime()
+ }
}
@Test
fun newEducationInfoOnMaxSignalCountReached() =
testScope.runTest {
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
val model by collectLastValue(underTest.educationTriggered)
- assertThat(model?.gestureType).isEqualTo(BACK)
+
+ assertThat(model?.gestureType).isEqualTo(gestureType)
}
@Test
fun newEducationToastOn1stEducation() =
testScope.runTest {
val model by collectLastValue(underTest.educationTriggered)
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
+
assertThat(model?.educationUiType).isEqualTo(EducationUiType.Toast)
}
@@ -93,12 +98,12 @@
fun newEducationNotificationOn2ndEducation() =
testScope.runTest {
val model by collectLastValue(underTest.educationTriggered)
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
// runCurrent() to trigger 1st education
runCurrent()
eduClock.offset(minDurationForNextEdu)
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
assertThat(model?.educationUiType).isEqualTo(EducationUiType.Notification)
}
@@ -106,7 +111,7 @@
@Test
fun noEducationInfoBeforeMaxSignalCountReached() =
testScope.runTest {
- contextualEduInteractor.incrementSignalCount(BACK)
+ contextualEduInteractor.incrementSignalCount(gestureType)
val model by collectLastValue(underTest.educationTriggered)
assertThat(model).isNull()
}
@@ -115,8 +120,8 @@
fun noEducationInfoWhenShortcutTriggeredPreviously() =
testScope.runTest {
val model by collectLastValue(underTest.educationTriggered)
- contextualEduInteractor.updateShortcutTriggerTime(BACK)
- triggerMaxEducationSignals(BACK)
+ contextualEduInteractor.updateShortcutTriggerTime(gestureType)
+ triggerMaxEducationSignals(gestureType)
assertThat(model).isNull()
}
@@ -124,12 +129,12 @@
fun no2ndEducationBeforeMinEduIntervalReached() =
testScope.runTest {
val models by collectValues(underTest.educationTriggered)
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
runCurrent()
// Offset a duration that is less than the required education interval
eduClock.offset(1.seconds)
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
runCurrent()
assertThat(models.filterNotNull().size).isEqualTo(1)
@@ -140,15 +145,15 @@
testScope.runTest {
val models by collectValues(underTest.educationTriggered)
// Trigger 2 educations
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
runCurrent()
eduClock.offset(minDurationForNextEdu)
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
runCurrent()
// Try triggering 3rd education
eduClock.offset(minDurationForNextEdu)
- triggerMaxEducationSignals(BACK)
+ triggerMaxEducationSignals(gestureType)
assertThat(models.filterNotNull().size).isEqualTo(2)
}
@@ -157,18 +162,21 @@
fun startNewUsageSessionWhen2ndSignalReceivedAfterSessionDeadline() =
testScope.runTest {
val model by
- collectLastValue(kosmos.contextualEducationRepository.readGestureEduModelFlow(BACK))
- contextualEduInteractor.incrementSignalCount(BACK)
+ collectLastValue(
+ kosmos.contextualEducationRepository.readGestureEduModelFlow(gestureType)
+ )
+ contextualEduInteractor.incrementSignalCount(gestureType)
eduClock.offset(KeyboardTouchpadEduInteractor.usageSessionDuration.plus(1.seconds))
val secondSignalReceivedTime = eduClock.instant()
- contextualEduInteractor.incrementSignalCount(BACK)
+ contextualEduInteractor.incrementSignalCount(gestureType)
assertThat(model)
.isEqualTo(
GestureEduModel(
signalCount = 1,
usageSessionStartTime = secondSignalReceivedTime,
- userId = 0
+ userId = 0,
+ gestureType = gestureType
)
)
}
@@ -252,22 +260,9 @@
@Test
fun updateShortcutTimeOnKeyboardShortcutTriggered() =
testScope.runTest {
- // runCurrent() to trigger inputManager#registerKeyGestureEventListener in the
- // interactor
- runCurrent()
- val listenerCaptor =
- ArgumentCaptor.forClass(InputManager.KeyGestureEventListener::class.java)
- verify(kosmos.mockEduInputManager)
- .registerKeyGestureEventListener(any(), listenerCaptor.capture())
-
- val allAppsKeyGestureEvent =
- KeyGestureEvent.Builder()
- .setDeviceId(1)
- .setModifierState(KeyEvent.META_META_ON)
- .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
- .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
- .build()
- listenerCaptor.value.onKeyGestureEvent(allAppsKeyGestureEvent)
+ // Only All Apps needs to update the keyboard shortcut
+ assumeTrue(gestureType == ALL_APPS)
+ kosmos.contextualEducationRepository.setKeyboardShortcutTriggered(ALL_APPS)
val model by
collectLastValue(
@@ -293,10 +288,18 @@
runCurrent()
}
+ private suspend fun setUpForDeviceConnection() {
+ contextualEduInteractor.updateKeyboardFirstConnectionTime()
+ contextualEduInteractor.updateTouchpadFirstConnectionTime()
+ }
+
companion object {
- private val USER_INFOS =
- listOf(
- UserInfo(101, "Second User", 0),
- )
+ private val USER_INFOS = listOf(UserInfo(101, "Second User", 0))
+
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getGestureTypes(): List<GestureType> {
+ return listOf(BACK, HOME, OVERVIEW, ALL_APPS)
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
index c4ac585..ab33269 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
@@ -37,6 +37,7 @@
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -69,6 +70,11 @@
@Before
fun setUp() {
+ testScope.launch {
+ interactor.updateKeyboardFirstConnectionTime()
+ interactor.updateTouchpadFirstConnectionTime()
+ }
+
val viewModel =
ContextualEduViewModel(
kosmos.applicationContext.resources,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
index 686b518..366b55d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt
@@ -23,6 +23,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityTransitionAnimator
+import com.android.systemui.classifier.falsingManager
import com.android.systemui.haptics.fakeVibratorHelper
import com.android.systemui.kosmos.testScope
import com.android.systemui.log.core.FakeLogBuffer
@@ -68,11 +69,13 @@
vibratorHelper.primitiveDurations[VibrationEffect.Composition.PRIMITIVE_SPIN] = spinDuration
whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(true)
+ kosmos.falsingManager.setFalseLongTap(false)
longPressEffect =
QSLongPressEffect(
vibratorHelper,
kosmos.keyguardStateController,
+ kosmos.falsingManager,
FakeLogBuffer.Factory.create(),
)
longPressEffect.callback = callback
@@ -180,11 +183,7 @@
// THEN the expected texture is played
val reverseHaptics =
- LongPressHapticBuilder.createReversedEffect(
- progress,
- lowTickDuration,
- effectDuration,
- )
+ LongPressHapticBuilder.createReversedEffect(progress, lowTickDuration, effectDuration)
assertThat(reverseHaptics).isNotNull()
assertThat(vibratorHelper.hasVibratedWithEffects(reverseHaptics!!)).isTrue()
}
@@ -224,6 +223,20 @@
}
@Test
+ fun onAnimationComplete_isFalseLongClick_effectEndsInIdleWithReset() =
+ testWhileInState(QSLongPressEffect.State.RUNNING_FORWARD) {
+ // GIVEN that the long-click is false
+ kosmos.falsingManager.setFalseLongTap(true)
+
+ // GIVEN that the animation completes
+ longPressEffect.handleAnimationComplete()
+
+ // THEN the long-press effect ends in the idle state and the properties are reset
+ assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE)
+ verify(callback, times(1)).onResetProperties()
+ }
+
+ @Test
fun onAnimationComplete_whenRunningBackwardsFromUp_endsWithFinishedReversingAndClick() =
testWhileInState(QSLongPressEffect.State.RUNNING_BACKWARDS_FROM_UP) {
// GIVEN that the animation completes
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
index 59f16d7..84b7f5c2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
@@ -17,17 +17,16 @@
package com.android.systemui.keyguard.domain.interactor
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.keyguard.data.repository.keyguardBlueprintRepository
import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
@@ -59,8 +58,8 @@
class KeyguardBlueprintInteractorTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
- private val underTest = kosmos.keyguardBlueprintInteractor
- private val keyguardBlueprintRepository = kosmos.keyguardBlueprintRepository
+ private val underTest by lazy { kosmos.keyguardBlueprintInteractor }
+ private val keyguardBlueprintRepository by lazy { kosmos.keyguardBlueprintRepository }
private val clockRepository by lazy { kosmos.fakeKeyguardClockRepository }
private val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
private val fingerprintPropertyRepository by lazy { kosmos.fakeFingerprintPropertyRepository }
@@ -75,7 +74,7 @@
sensorId = 1,
strength = SensorStrength.STRONG,
sensorType = FingerprintSensorType.POWER_BUTTON,
- sensorLocations = mapOf()
+ sensorLocations = mapOf(),
)
}
@@ -93,7 +92,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+ @DisableSceneContainer
fun testAppliesSplitShadeBlueprint() {
testScope.runTest {
val blueprintId by collectLastValue(underTest.blueprintId)
@@ -107,7 +106,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+ @EnableSceneContainer
fun testDoesNotApplySplitShadeBlueprint() {
testScope.runTest {
val blueprintId by collectLastValue(underTest.blueprintId)
@@ -122,7 +121,7 @@
}
@Test
- @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+ @DisableSceneContainer
fun fingerprintPropertyInitialized_updatesBlueprint() {
testScope.runTest {
underTest.start()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
index 1981a2d..41cc953 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt
@@ -25,7 +25,7 @@
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.DismissAction
@@ -39,8 +39,6 @@
import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.data.repository.setSceneTransition
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.domain.resolver.notifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.quickSettingsSceneFamilyResolver
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.testKosmos
@@ -79,12 +77,9 @@
dismissInteractor = dismissInteractor,
applicationScope = testScope.backgroundScope,
sceneInteractor = { kosmos.sceneInteractor },
- deviceEntryInteractor = { kosmos.deviceEntryInteractor },
- quickSettingsSceneFamilyResolver = { kosmos.quickSettingsSceneFamilyResolver },
- notifShadeSceneFamilyResolver = { kosmos.notifShadeSceneFamilyResolver },
+ deviceUnlockedInteractor = { kosmos.deviceUnlockedInteractor },
powerInteractor = kosmos.powerInteractor,
alternateBouncerInteractor = kosmos.alternateBouncerInteractor,
- keyguardInteractor = { kosmos.keyguardInteractor },
shadeInteractor = { kosmos.shadeInteractor },
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 5a6f2be..77106ae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -137,9 +137,7 @@
@JvmStatic
@Parameters(name = "{0}")
fun getParams(): List<FlagsParameterization> {
- return FlagsParameterization.allCombinationsOf(
- FLAG_COMMUNAL_SCENE_KTF_REFACTOR,
- )
+ return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_SCENE_KTF_REFACTOR)
.andSceneContainer()
}
}
@@ -157,9 +155,7 @@
mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
if (!SceneContainerFlag.isEnabled) {
- mSetFlagsRule.disableFlags(
- Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
- )
+ mSetFlagsRule.disableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
}
featureFlags = FakeFeatureFlags()
@@ -194,7 +190,7 @@
ownerName =
"FromLockscreenTransitionInteractor" +
"(#listenForLockscreenToPrimaryBouncer)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -219,7 +215,7 @@
to = KeyguardState.DOZING,
from = KeyguardState.OCCLUDED,
ownerName = "FromOccludedTransitionInteractor(Sleep transition triggered)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -244,7 +240,7 @@
to = KeyguardState.AOD,
from = KeyguardState.OCCLUDED,
ownerName = "FromOccludedTransitionInteractor(Sleep transition triggered)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -273,7 +269,7 @@
to = KeyguardState.DREAMING,
from = KeyguardState.LOCKSCREEN,
ownerName = "FromLockscreenTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -303,7 +299,7 @@
to = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
from = KeyguardState.LOCKSCREEN,
ownerName = "FromLockscreenTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -328,7 +324,7 @@
to = KeyguardState.DOZING,
from = KeyguardState.LOCKSCREEN,
ownerName = "FromLockscreenTransitionInteractor(Sleep transition triggered)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -353,7 +349,7 @@
to = KeyguardState.AOD,
from = KeyguardState.LOCKSCREEN,
ownerName = "FromLockscreenTransitionInteractor(Sleep transition triggered)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -373,7 +369,7 @@
// GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
runTransitionAndSetWakefulness(
KeyguardState.GONE,
- KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
)
// WHEN the lockscreen hosted dream stops
@@ -385,7 +381,7 @@
to = KeyguardState.LOCKSCREEN,
from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -398,7 +394,7 @@
// GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
runTransitionAndSetWakefulness(
KeyguardState.GONE,
- KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
)
// WHEN biometrics succeeds with wake and unlock from dream mode
@@ -412,7 +408,7 @@
to = KeyguardState.GONE,
from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -429,7 +425,7 @@
// GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
runTransitionAndSetWakefulness(
KeyguardState.GONE,
- KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
)
// WHEN the primary bouncer is set to show
@@ -441,7 +437,7 @@
to = KeyguardState.PRIMARY_BOUNCER,
from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -458,7 +454,7 @@
// GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
runTransitionAndSetWakefulness(
KeyguardState.GONE,
- KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
)
// WHEN the device begins to sleep
@@ -473,7 +469,7 @@
to = KeyguardState.DOZING,
from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -491,7 +487,7 @@
// GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED
runTransitionAndSetWakefulness(
KeyguardState.GONE,
- KeyguardState.DREAMING_LOCKSCREEN_HOSTED
+ KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
)
// WHEN the keyguard is occluded and the lockscreen hosted dream stops
@@ -504,7 +500,7 @@
to = KeyguardState.OCCLUDED,
from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
ownerName = "FromDreamingLockscreenHostedTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -526,7 +522,7 @@
.startedTransition(
to = KeyguardState.LOCKSCREEN,
from = KeyguardState.DOZING,
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -538,7 +534,7 @@
transitionRepository.sendTransitionSteps(
KeyguardState.LOCKSCREEN,
KeyguardState.DOZING,
- testScheduler
+ testScheduler,
)
// GIVEN a prior transition has started to LOCKSCREEN
transitionRepository.sendTransitionStep(
@@ -591,7 +587,7 @@
to = KeyguardState.GONE,
from = KeyguardState.DOZING,
ownerName = "FromDozingTransitionInteractor(biometric wake and unlock)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -615,7 +611,7 @@
.startedTransition(
from = KeyguardState.DOZING,
to = KeyguardState.PRIMARY_BOUNCER,
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -645,7 +641,7 @@
to = KeyguardState.GONE,
from = KeyguardState.DREAMING,
ownerName = "FromDreamingTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -677,7 +673,7 @@
.startedTransition(
from = KeyguardState.DOZING,
to = KeyguardState.GLANCEABLE_HUB,
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -703,7 +699,7 @@
to = KeyguardState.DOZING,
from = KeyguardState.GONE,
ownerName = "FromGoneTransitionInteractor(Sleep transition triggered)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -729,7 +725,7 @@
to = KeyguardState.AOD,
from = KeyguardState.GONE,
ownerName = "FromGoneTransitionInteractor(Sleep transition triggered)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -751,7 +747,7 @@
to = KeyguardState.LOCKSCREEN,
from = KeyguardState.GONE,
ownerName = "FromGoneTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -775,7 +771,7 @@
to = KeyguardState.OCCLUDED,
ownerName =
"FromGoneTransitionInteractor" + "(Dismissible keyguard with occlusion)",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -800,7 +796,7 @@
to = KeyguardState.DREAMING,
from = KeyguardState.GONE,
ownerName = "FromGoneTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -831,7 +827,7 @@
to = KeyguardState.GLANCEABLE_HUB,
from = KeyguardState.GONE,
ownerName = FromGoneTransitionInteractor::class.simpleName,
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -854,7 +850,7 @@
to = KeyguardState.GLANCEABLE_HUB,
from = KeyguardState.GONE,
ownerName = CommunalSceneTransitionInteractor::class.simpleName,
- animatorAssertion = { it.isNull() }
+ animatorAssertion = { it.isNull() },
)
coroutineContext.cancelChildren()
@@ -867,7 +863,7 @@
// GIVEN a prior transition has run to ALTERNATE_BOUNCER
runTransitionAndSetWakefulness(
KeyguardState.LOCKSCREEN,
- KeyguardState.ALTERNATE_BOUNCER
+ KeyguardState.ALTERNATE_BOUNCER,
)
// WHEN the alternateBouncer stops showing and then the primary bouncer shows
@@ -879,7 +875,7 @@
to = KeyguardState.PRIMARY_BOUNCER,
from = KeyguardState.ALTERNATE_BOUNCER,
ownerName = "FromAlternateBouncerTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -892,7 +888,7 @@
bouncerRepository.setAlternateVisible(true)
runTransitionAndSetWakefulness(
KeyguardState.LOCKSCREEN,
- KeyguardState.ALTERNATE_BOUNCER
+ KeyguardState.ALTERNATE_BOUNCER,
)
// GIVEN the primary bouncer isn't showing, aod available and starting to sleep
@@ -909,7 +905,7 @@
to = KeyguardState.AOD,
from = KeyguardState.ALTERNATE_BOUNCER,
ownerName = "FromAlternateBouncerTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -922,7 +918,7 @@
bouncerRepository.setAlternateVisible(true)
runTransitionAndSetWakefulness(
KeyguardState.LOCKSCREEN,
- KeyguardState.ALTERNATE_BOUNCER
+ KeyguardState.ALTERNATE_BOUNCER,
)
// GIVEN the primary bouncer isn't showing, aod not available and starting to sleep
@@ -940,7 +936,7 @@
to = KeyguardState.DOZING,
from = KeyguardState.ALTERNATE_BOUNCER,
ownerName = "FromAlternateBouncerTransitionInteractor",
- animatorAssertion = { it.isNotNull() }
+ animatorAssertion = { it.isNotNull() },
)
coroutineContext.cancelChildren()
@@ -953,7 +949,7 @@
bouncerRepository.setAlternateVisible(true)
runTransitionAndSetWakefulness(
KeyguardState.LOCKSCREEN,
- KeyguardState.ALTERNATE_BOUNCER
+ KeyguardState.ALTERNATE_BOUNCER,
)
// GIVEN the primary bouncer isn't showing and device not sleeping
@@ -982,7 +978,7 @@
bouncerRepository.setAlternateVisible(true)
runTransitionAndSetWakefulness(
KeyguardState.LOCKSCREEN,
- KeyguardState.ALTERNATE_BOUNCER
+ KeyguardState.ALTERNATE_BOUNCER,
)
// GIVEN the keyguard is going away
@@ -1013,7 +1009,7 @@
bouncerRepository.setAlternateVisible(true)
runTransitionAndSetWakefulness(
KeyguardState.LOCKSCREEN,
- KeyguardState.ALTERNATE_BOUNCER
+ KeyguardState.ALTERNATE_BOUNCER,
)
// GIVEN the primary bouncer isn't showing and device not sleeping
@@ -1131,7 +1127,7 @@
bouncerRepository.setPrimaryShow(true)
runTransitionAndSetWakefulness(
KeyguardState.GLANCEABLE_HUB,
- KeyguardState.PRIMARY_BOUNCER
+ KeyguardState.PRIMARY_BOUNCER,
)
// WHEN the primaryBouncer stops showing
@@ -1165,7 +1161,7 @@
bouncerRepository.setPrimaryShow(true)
runTransitionAndSetWakefulness(
KeyguardState.GLANCEABLE_HUB,
- KeyguardState.PRIMARY_BOUNCER
+ KeyguardState.PRIMARY_BOUNCER,
)
// GIVEN that we are dreaming and occluded
@@ -1190,36 +1186,6 @@
}
@Test
- @DisableSceneContainer
- fun primaryBouncerToDreamingLockscreenHosted() =
- testScope.runTest {
- // GIVEN device dreaming with the lockscreen hosted dream and not dozing
- keyguardRepository.setIsActiveDreamLockscreenHosted(true)
-
- // GIVEN a prior transition has run to PRIMARY_BOUNCER
- bouncerRepository.setPrimaryShow(true)
- runTransitionAndSetWakefulness(
- KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
- KeyguardState.PRIMARY_BOUNCER
- )
-
- // WHEN the primary bouncer stops showing and lockscreen hosted dream still active
- bouncerRepository.setPrimaryShow(false)
- runCurrent()
-
- // THEN a transition back to DREAMING_LOCKSCREEN_HOSTED should occur
- assertThat(transitionRepository)
- .startedTransition(
- ownerName = "FromPrimaryBouncerTransitionInteractor",
- from = KeyguardState.PRIMARY_BOUNCER,
- to = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
- animatorAssertion = { it.isNotNull() },
- )
-
- coroutineContext.cancelChildren()
- }
-
- @Test
@BrokenWithSceneContainer(339465026)
fun occludedToGone() =
testScope.runTest {
@@ -1585,10 +1551,7 @@
// WHEN the device starts DOZE_AOD
keyguardRepository.setDozeTransitionModel(
- DozeTransitionModel(
- from = DozeStateModel.INITIALIZED,
- to = DozeStateModel.DOZE_AOD,
- )
+ DozeTransitionModel(from = DozeStateModel.INITIALIZED, to = DozeStateModel.DOZE_AOD)
)
runCurrent()
@@ -2268,7 +2231,7 @@
private suspend fun TestScope.runTransitionAndSetWakefulness(
from: KeyguardState,
- to: KeyguardState
+ to: KeyguardState,
) {
transitionRepository.sendTransitionStep(
TransitionStep(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
index 41c5b73..ff6ea3a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt
@@ -25,6 +25,8 @@
import com.android.systemui.Flags as AConfigFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
@@ -44,6 +46,7 @@
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.runTest
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Answers
@@ -71,10 +74,8 @@
private val burnInFlow = MutableStateFlow(BurnInModel())
@Before
- @DisableFlags(
- AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
- AConfigFlags.FLAG_COMPOSE_LOCKSCREEN
- )
+ @DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ @DisableSceneContainer
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(burnInInteractor.burnIn(anyInt(), anyInt())).thenReturn(burnInFlow)
@@ -112,18 +113,13 @@
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
value = 1f,
- transitionState = TransitionState.FINISHED
+ transitionState = TransitionState.FINISHED,
),
validateStep = false,
)
// Trigger a change to the burn-in model
- burnInFlow.value =
- BurnInModel(
- translationX = 20,
- translationY = 30,
- scale = 0.5f,
- )
+ burnInFlow.value = BurnInModel(translationX = 20, translationY = 30, scale = 0.5f)
assertThat(movement?.translationX).isEqualTo(0)
assertThat(movement?.translationY).isEqualTo(0)
@@ -143,17 +139,12 @@
from = KeyguardState.GONE,
to = KeyguardState.AOD,
value = 1f,
- transitionState = TransitionState.FINISHED
+ transitionState = TransitionState.FINISHED,
),
validateStep = false,
)
// Trigger a change to the burn-in model
- burnInFlow.value =
- BurnInModel(
- translationX = 20,
- translationY = 30,
- scale = 0.5f,
- )
+ burnInFlow.value = BurnInModel(translationX = 20, translationY = 30, scale = 0.5f)
assertThat(movement?.translationX).isEqualTo(20)
assertThat(movement?.translationY).isEqualTo(30)
@@ -166,7 +157,7 @@
from = KeyguardState.GONE,
to = KeyguardState.AOD,
value = 0f,
- transitionState = TransitionState.STARTED
+ transitionState = TransitionState.STARTED,
),
validateStep = false,
)
@@ -180,11 +171,7 @@
@DisableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
fun translationAndScale_whenFullyDozing_MigrationFlagOff_staysOutOfTopInset() =
testScope.runTest {
- burnInParameters =
- burnInParameters.copy(
- minViewY = 100,
- topInset = 80,
- )
+ burnInParameters = burnInParameters.copy(minViewY = 100, topInset = 80)
val movement by collectLastValue(underTest.movement(burnInParameters))
// Set to dozing (on AOD)
@@ -193,18 +180,13 @@
from = KeyguardState.GONE,
to = KeyguardState.AOD,
value = 1f,
- transitionState = TransitionState.FINISHED
+ transitionState = TransitionState.FINISHED,
),
validateStep = false,
)
// Trigger a change to the burn-in model
- burnInFlow.value =
- BurnInModel(
- translationX = 20,
- translationY = -30,
- scale = 0.5f,
- )
+ burnInFlow.value = BurnInModel(translationX = 20, translationY = -30, scale = 0.5f)
assertThat(movement?.translationX).isEqualTo(20)
// -20 instead of -30, due to inset of 80
assertThat(movement?.translationY).isEqualTo(-20)
@@ -217,7 +199,7 @@
from = KeyguardState.GONE,
to = KeyguardState.AOD,
value = 0f,
- transitionState = TransitionState.STARTED
+ transitionState = TransitionState.STARTED,
),
validateStep = false,
)
@@ -231,11 +213,7 @@
@EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
fun translationAndScale_whenFullyDozing_MigrationFlagOn_staysOutOfTopInset() =
testScope.runTest {
- burnInParameters =
- burnInParameters.copy(
- minViewY = 100,
- topInset = 80,
- )
+ burnInParameters = burnInParameters.copy(minViewY = 100, topInset = 80)
val movement by collectLastValue(underTest.movement(burnInParameters))
// Set to dozing (on AOD)
@@ -244,18 +222,13 @@
from = KeyguardState.GONE,
to = KeyguardState.AOD,
value = 1f,
- transitionState = TransitionState.FINISHED
+ transitionState = TransitionState.FINISHED,
),
validateStep = false,
)
// Trigger a change to the burn-in model
- burnInFlow.value =
- BurnInModel(
- translationX = 20,
- translationY = -30,
- scale = 0.5f,
- )
+ burnInFlow.value = BurnInModel(translationX = 20, translationY = -30, scale = 0.5f)
assertThat(movement?.translationX).isEqualTo(20)
// -20 instead of -30, due to inset of 80
assertThat(movement?.translationY).isEqualTo(-20)
@@ -268,7 +241,7 @@
from = KeyguardState.GONE,
to = KeyguardState.AOD,
value = 0f,
- transitionState = TransitionState.STARTED
+ transitionState = TransitionState.STARTED,
),
validateStep = false,
)
@@ -291,18 +264,13 @@
from = KeyguardState.GONE,
to = KeyguardState.AOD,
value = 1f,
- transitionState = TransitionState.FINISHED
+ transitionState = TransitionState.FINISHED,
),
validateStep = false,
)
// Trigger a change to the burn-in model
- burnInFlow.value =
- BurnInModel(
- translationX = 20,
- translationY = 30,
- scale = 0.5f,
- )
+ burnInFlow.value = BurnInModel(translationX = 20, translationY = 30, scale = 0.5f)
assertThat(movement?.translationX).isEqualTo(20)
assertThat(movement?.translationY).isEqualTo(30)
@@ -311,9 +279,9 @@
}
@Test
- @DisableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+ @DisableSceneContainer
@EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
- fun translationAndScale_composeFlagOff_weatherLargeClock() =
+ fun translationAndScale_sceneContainerOff_weatherLargeClock() =
testBurnInViewModelForClocks(
isSmallClock = false,
isWeatherClock = true,
@@ -321,9 +289,9 @@
)
@Test
- @DisableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+ @DisableSceneContainer
@EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
- fun translationAndScale_composeFlagOff_weatherSmallClock() =
+ fun translationAndScale_sceneContainerOff_weatherSmallClock() =
testBurnInViewModelForClocks(
isSmallClock = true,
isWeatherClock = true,
@@ -331,9 +299,9 @@
)
@Test
- @DisableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+ @DisableSceneContainer
@EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
- fun translationAndScale_composeFlagOff_nonWeatherLargeClock() =
+ fun translationAndScale_sceneContainerOff_nonWeatherLargeClock() =
testBurnInViewModelForClocks(
isSmallClock = false,
isWeatherClock = false,
@@ -341,9 +309,9 @@
)
@Test
- @DisableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN)
+ @DisableSceneContainer
@EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
- fun translationAndScale_composeFlagOff_nonWeatherSmallClock() =
+ fun translationAndScale_sceneContainerOff_nonWeatherSmallClock() =
testBurnInViewModelForClocks(
isSmallClock = true,
isWeatherClock = false,
@@ -351,11 +319,9 @@
)
@Test
- @EnableFlags(
- AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
- AConfigFlags.FLAG_COMPOSE_LOCKSCREEN
- )
- fun translationAndScale_composeFlagOn_weatherLargeClock() =
+ @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ @EnableSceneContainer
+ fun translationAndScale_sceneContainerOn_weatherLargeClock() =
testBurnInViewModelForClocks(
isSmallClock = false,
isWeatherClock = true,
@@ -363,11 +329,9 @@
)
@Test
- @EnableFlags(
- AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
- AConfigFlags.FLAG_COMPOSE_LOCKSCREEN
- )
- fun translationAndScale_composeFlagOn_weatherSmallClock() =
+ @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ @EnableSceneContainer
+ fun translationAndScale_sceneContainerOn_weatherSmallClock() =
testBurnInViewModelForClocks(
isSmallClock = true,
isWeatherClock = true,
@@ -375,11 +339,9 @@
)
@Test
- @EnableFlags(
- AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
- AConfigFlags.FLAG_COMPOSE_LOCKSCREEN
- )
- fun translationAndScale_composeFlagOn_nonWeatherLargeClock() =
+ @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ @EnableSceneContainer
+ fun translationAndScale_sceneContainerOn_nonWeatherLargeClock() =
testBurnInViewModelForClocks(
isSmallClock = false,
isWeatherClock = false,
@@ -387,11 +349,10 @@
)
@Test
- @EnableFlags(
- AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
- AConfigFlags.FLAG_COMPOSE_LOCKSCREEN
- )
- fun translationAndScale_composeFlagOn_nonWeatherSmallClock() =
+ @EnableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
+ @EnableSceneContainer
+ @Ignore("b/367659687")
+ fun translationAndScale_sceneContainerOn_nonWeatherSmallClock() =
testBurnInViewModelForClocks(
isSmallClock = true,
isWeatherClock = false,
@@ -421,18 +382,13 @@
from = KeyguardState.LOCKSCREEN,
to = KeyguardState.AOD,
value = 1f,
- transitionState = TransitionState.FINISHED
+ transitionState = TransitionState.FINISHED,
),
validateStep = false,
)
// Trigger a change to the burn-in model
- burnInFlow.value =
- BurnInModel(
- translationX = 20,
- translationY = 30,
- scale = 0.5f,
- )
+ burnInFlow.value = BurnInModel(translationX = 20, translationY = 30, scale = 0.5f)
assertThat(movement?.translationX).isEqualTo(20)
assertThat(movement?.translationY).isEqualTo(30)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
index 17e1b53..05a6b87 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt
@@ -16,14 +16,13 @@
package com.android.systemui.keyguard.ui.viewmodel
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.BrokenWithSceneContainer
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
import com.android.systemui.keyguard.data.repository.keyguardClockRepository
@@ -229,8 +228,8 @@
}
@Test
- @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
- fun testSmallClockTop_splitShade_composeLockscreenOn() =
+ @EnableSceneContainer
+ fun testSmallClockTop_splitShade_sceneContainerOn() =
testScope.runTest {
with(kosmos) {
shadeRepository.setShadeLayoutWide(true)
@@ -244,8 +243,8 @@
}
@Test
- @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
- fun testSmallClockTop_splitShade_composeLockscreenOff() =
+ @DisableSceneContainer
+ fun testSmallClockTop_splitShade_sceneContainerOff() =
testScope.runTest {
with(kosmos) {
shadeRepository.setShadeLayoutWide(true)
@@ -257,8 +256,8 @@
}
@Test
- @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
- fun testSmallClockTop_nonSplitShade_composeLockscreenOn() =
+ @EnableSceneContainer
+ fun testSmallClockTop_nonSplitShade_sceneContainerOn() =
testScope.runTest {
with(kosmos) {
shadeRepository.setShadeLayoutWide(false)
@@ -270,8 +269,8 @@
}
@Test
- @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
- fun testSmallClockTop_nonSplitShade_composeLockscreenOff() =
+ @DisableSceneContainer
+ fun testSmallClockTop_nonSplitShade_sceneContainerOff() =
testScope.runTest {
with(kosmos) {
shadeRepository.setShadeLayoutWide(false)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoaderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoaderTest.kt
index 69ccc58..7da2e9a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoaderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoaderTest.kt
@@ -35,6 +35,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.Flags.MEDIA_RESUME_PROGRESS
import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.graphics.ImageLoader
import com.android.systemui.graphics.imageLoader
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -45,12 +46,18 @@
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
private const val KEY = "KEY"
@@ -88,12 +95,13 @@
mediaControllerFactory,
mediaFlags,
kosmos.imageLoader,
- statusBarManager
+ statusBarManager,
)
@Before
fun setUp() {
mediaControllerFactory.setControllerForToken(session.sessionToken, mediaController)
+ whenever(mediaController.metadata).then { metadataBuilder.build() }
}
@Test
@@ -115,7 +123,7 @@
0,
0,
AudioAttributes.Builder().build(),
- null
+ null,
)
)
whenever(mediaController.metadata)
@@ -126,7 +134,7 @@
.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, albumArt)
.putLong(
MediaConstants.METADATA_KEY_IS_EXPLICIT,
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT,
)
.build()
)
@@ -161,12 +169,12 @@
val extras = Bundle()
extras.putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
- MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
+ MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED,
)
extras.putDouble(MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.3)
extras.putLong(
MediaConstants.METADATA_KEY_IS_EXPLICIT,
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT,
)
val description =
@@ -189,7 +197,7 @@
session.sessionToken,
APP_NAME,
intent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
assertThat(result).isNotNull()
assertThat(result?.appName).isEqualTo(APP_NAME)
@@ -372,9 +380,37 @@
assertThat(result).isNotNull()
}
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ fun testLoadMediaDataInBg_cancelMultipleScheduledTasks() =
+ testScope.runTest {
+ val mockImageLoader = mock<ImageLoader>()
+ val mediaDataLoader =
+ MediaDataLoader(
+ context,
+ testDispatcher,
+ testScope,
+ mediaControllerFactory,
+ mediaFlags,
+ mockImageLoader,
+ statusBarManager,
+ )
+ metadataBuilder.putString(
+ MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
+ "content://album_art_uri",
+ )
+
+ testScope.launch { mediaDataLoader.loadMediaData(KEY, createMediaNotification()) }
+ testScope.launch { mediaDataLoader.loadMediaData(KEY, createMediaNotification()) }
+ testScope.launch { mediaDataLoader.loadMediaData(KEY, createMediaNotification()) }
+ testScope.advanceUntilIdle()
+
+ verify(mockImageLoader, times(1)).loadBitmap(any(), anyInt(), anyInt(), anyInt())
+ }
+
private fun createMediaNotification(
mediaSession: MediaSession? = session,
- applicationInfo: ApplicationInfo? = null
+ applicationInfo: ApplicationInfo? = null,
): StatusBarNotification =
SbnBuilder().run {
setPkg(PACKAGE_NAME)
@@ -385,7 +421,7 @@
val bundle = Bundle()
bundle.putParcelable(
Notification.EXTRA_BUILDER_APPLICATION_INFO,
- applicationInfo
+ applicationInfo,
)
it.addExtras(bundle)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
index f6865f13..642d9a0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModelTest.kt
@@ -21,6 +21,7 @@
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -28,6 +29,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayActionsViewModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -47,7 +49,7 @@
private val underTest = kosmos.notificationsShadeOverlayActionsViewModel
@Test
- fun upTransitionSceneKey_hidesShade() =
+ fun up_hidesShade() =
testScope.runTest {
val actions by collectLastValue(underTest.actions)
underTest.activateIn(this)
@@ -66,4 +68,22 @@
assertThat((actions?.get(Back) as? UserActionResult.HideOverlay)?.overlay)
.isEqualTo(Overlays.NotificationsShade)
}
+
+ @Test
+ fun downFromTopRight_switchesToQuickSettingsShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ underTest.activateIn(this)
+
+ assertThat(
+ (actions?.get(
+ Swipe(
+ direction = SwipeDirection.Down,
+ fromSource = SceneContainerEdge.TopRight,
+ )
+ ) as? UserActionResult.ReplaceByOverlay)
+ ?.overlay
+ )
+ .isEqualTo(Overlays.QuickSettingsShade)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
deleted file mode 100644
index 42db96e..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.domain.interactor
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
-import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
-import com.android.systemui.qs.panels.data.repository.gridLayoutTypeRepository
-import com.android.systemui.qs.panels.shared.model.GridLayoutType
-import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
-import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
-import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.testKosmos
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class GridConsistencyInteractorTest : SysuiTestCase() {
-
- data object NoopGridLayoutType : GridLayoutType
-
- private val kosmos =
- testKosmos().apply {
- defaultLargeTilesRepository =
- object : DefaultLargeTilesRepository {
- override val defaultLargeTiles =
- setOf(
- TileSpec.create("largeA"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("largeD"),
- )
- }
- gridConsistencyInteractorsMap =
- mapOf(
- Pair(NoopGridLayoutType, noopGridConsistencyInteractor),
- Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor)
- )
- }
-
- private val underTest = with(kosmos) { gridConsistencyInteractor }
-
- @Before
- fun setUp() {
- // Mostly testing InfiniteGridConsistencyInteractor because it reorders tiles
- with(kosmos) { gridLayoutTypeRepository.setLayout(InfiniteGridLayoutType) }
- underTest.start()
- }
-
- @OptIn(ExperimentalCoroutinesApi::class)
- @Test
- fun changeLayoutType_usesCorrectGridConsistencyInteractor() =
- with(kosmos) {
- testScope.runTest {
- // Using the no-op grid consistency interactor
- gridLayoutTypeRepository.setLayout(NoopGridLayoutType)
-
- // Setting an invalid layout with holes
- // [ Large A ] [ sa ]
- // [ Large B ] [ Large C ]
- // [ sb ] [ Large D ]
- val newTiles =
- listOf(
- TileSpec.create("largeA"),
- TileSpec.create("smallA"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("smallB"),
- TileSpec.create("largeD"),
- )
- tileSpecRepository.setTiles(0, newTiles)
-
- runCurrent()
-
- val tiles = currentTilesInteractor.currentTiles.value
- val tileSpecs = tiles.map { it.spec }
-
- // Saved tiles should be unchanged
- assertThat(tileSpecs).isEqualTo(newTiles)
- }
- }
-
- @Test
- fun validTilesWithInfiniteGridConsistencyInteractor_unchangedList() =
- with(kosmos) {
- testScope.runTest {
- // Setting a valid layout with holes
- // [ Large A ] [ sa ][ sb ]
- // [ Large B ] [ Large C ]
- // [ Large D ]
- val newTiles =
- listOf(
- TileSpec.create("largeA"),
- TileSpec.create("smallA"),
- TileSpec.create("smallB"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("largeD"),
- )
- tileSpecRepository.setTiles(0, newTiles)
-
- runCurrent()
-
- val tiles = currentTilesInteractor.currentTiles.value
- val tileSpecs = tiles.map { it.spec }
-
- // Saved tiles should be unchanged
- assertThat(tileSpecs).isEqualTo(newTiles)
- }
- }
-
- @Test
- fun invalidTilesWithInfiniteGridConsistencyInteractor_savesNewList() =
- with(kosmos) {
- testScope.runTest {
- // Setting an invalid layout with holes
- // [ sa ] [ Large A ]
- // [ Large B ] [ sb ] [ sc ]
- // [ sd ] [ se ] [ Large C ]
- val newTiles =
- listOf(
- TileSpec.create("smallA"),
- TileSpec.create("largeA"),
- TileSpec.create("largeB"),
- TileSpec.create("smallB"),
- TileSpec.create("smallC"),
- TileSpec.create("smallD"),
- TileSpec.create("smallE"),
- TileSpec.create("largeC"),
- )
- tileSpecRepository.setTiles(0, newTiles)
-
- runCurrent()
-
- val tiles = currentTilesInteractor.currentTiles.value
- val tileSpecs = tiles.map { it.spec }
-
- // Expected grid
- // [ sa ] [ Large A ] [ sb ]
- // [ Large B ] [ sc ] [ sd ]
- // [ se ] [ Large C ]
- val expectedTiles =
- listOf(
- TileSpec.create("smallA"),
- TileSpec.create("largeA"),
- TileSpec.create("smallB"),
- TileSpec.create("largeB"),
- TileSpec.create("smallC"),
- TileSpec.create("smallD"),
- TileSpec.create("smallE"),
- TileSpec.create("largeC"),
- )
-
- // Saved tiles should be unchanged
- assertThat(tileSpecs).isEqualTo(expectedTiles)
- }
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt
deleted file mode 100644
index ea51398..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.domain.interactor
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
-import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.testKosmos
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class InfiniteGridConsistencyInteractorTest : SysuiTestCase() {
-
- private val kosmos =
- testKosmos().apply {
- defaultLargeTilesRepository =
- object : DefaultLargeTilesRepository {
- override val defaultLargeTiles: Set<TileSpec> =
- setOf(
- TileSpec.create("largeA"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("largeD"),
- )
- }
- }
- private val underTest = with(kosmos) { infiniteGridConsistencyInteractor }
-
- @Test
- fun validTiles_returnsUnchangedList() =
- with(kosmos) {
- testScope.runTest {
- // Original grid
- // [ Large A ] [ sa ][ sb ]
- // [ Large B ] [ Large C ]
- // [ Large D ]
- val tiles =
- listOf(
- TileSpec.create("largeA"),
- TileSpec.create("smallA"),
- TileSpec.create("smallB"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("largeD"),
- )
-
- val newTiles = underTest.reconcileTiles(tiles)
-
- assertThat(newTiles).isEqualTo(tiles)
- }
- }
-
- @Test
- fun invalidTiles_moveIconTileForward() =
- with(kosmos) {
- testScope.runTest {
- // Original grid
- // [ Large A ] [ sa ]
- // [ Large B ] [ Large C ]
- // [ sb ] [ Large D ]
- val tiles =
- listOf(
- TileSpec.create("largeA"),
- TileSpec.create("smallA"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("smallB"),
- TileSpec.create("largeD"),
- )
- // Expected grid
- // [ Large A ] [ sa ][ sb ]
- // [ Large B ] [ Large C ]
- // [ Large D ]
- val expectedTiles =
- listOf(
- TileSpec.create("largeA"),
- TileSpec.create("smallA"),
- TileSpec.create("smallB"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("largeD"),
- )
-
- val newTiles = underTest.reconcileTiles(tiles)
-
- assertThat(newTiles).isEqualTo(expectedTiles)
- }
- }
-
- @Test
- fun invalidTiles_moveIconTileBack() =
- with(kosmos) {
- testScope.runTest {
- // Original grid
- // [ sa ] [ Large A ]
- // [ Large B ] [ Large C ]
- // [ Large D ]
- val tiles =
- listOf(
- TileSpec.create("smallA"),
- TileSpec.create("largeA"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("largeD"),
- )
- // Expected grid
- // [ Large A ] [ Large B ]
- // [ Large C ] [ Large D ]
- // [ sa ]
- val expectedTiles =
- listOf(
- TileSpec.create("largeA"),
- TileSpec.create("largeB"),
- TileSpec.create("largeC"),
- TileSpec.create("largeD"),
- TileSpec.create("smallA"),
- )
-
- val newTiles = underTest.reconcileTiles(tiles)
-
- assertThat(newTiles).isEqualTo(expectedTiles)
- }
- }
-
- @Test
- fun invalidTiles_multipleCorrections() =
- with(kosmos) {
- testScope.runTest {
- // Original grid
- // [ sa ] [ Large A ]
- // [ Large B ] [ sb ] [ sc ]
- // [ sd ] [ se ] [ Large C ]
- val tiles =
- listOf(
- TileSpec.create("smallA"),
- TileSpec.create("largeA"),
- TileSpec.create("largeB"),
- TileSpec.create("smallB"),
- TileSpec.create("smallC"),
- TileSpec.create("smallD"),
- TileSpec.create("smallE"),
- TileSpec.create("largeC"),
- )
- // Expected grid
- // [ sa ] [ Large A ] [ sb ]
- // [ Large B ] [ sc ] [ sd ]
- // [ se ] [ Large C ]
- val expectedTiles =
- listOf(
- TileSpec.create("smallA"),
- TileSpec.create("largeA"),
- TileSpec.create("smallB"),
- TileSpec.create("largeB"),
- TileSpec.create("smallC"),
- TileSpec.create("smallD"),
- TileSpec.create("smallE"),
- TileSpec.create("largeC"),
- )
-
- val newTiles = underTest.reconcileTiles(tiles)
-
- assertThat(newTiles).isEqualTo(expectedTiles)
- }
- }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt
index 53384af..9e90090 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt
@@ -22,6 +22,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository
import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout
import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.fixedColumnsSizeViewModel
import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel
@@ -44,12 +45,7 @@
}
private val underTest =
- with(kosmos) {
- InfiniteGridLayout(
- iconTilesViewModel,
- fixedColumnsSizeViewModel,
- )
- }
+ with(kosmos) { InfiniteGridLayout(iconTilesViewModel, fixedColumnsSizeViewModel) }
@Test
fun correctPagination_underOnePage_sameOrder() =
@@ -65,7 +61,7 @@
smallTile(),
largeTile(),
largeTile(),
- smallTile()
+ smallTile(),
)
val pages = underTest.splitIntoPages(tiles, rows = rows, columns = columns)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt
new file mode 100644
index 0000000..b144f06
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiStateTest.kt
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.viewmodel
+
+import android.content.res.Resources
+import android.content.res.mainResources
+import android.service.quicksettings.Tile
+import android.widget.Button
+import android.widget.Switch
+import androidx.compose.ui.semantics.Role
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TileUiStateTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val resources: Resources
+ get() = kosmos.mainResources
+
+ @Test
+ fun stateUnavailable_secondaryLabelNotmodified() {
+ val testString = "TEST STRING"
+ val state =
+ QSTile.State().apply {
+ state = Tile.STATE_UNAVAILABLE
+ secondaryLabel = testString
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.state).isEqualTo(Tile.STATE_UNAVAILABLE)
+ }
+
+ @Test
+ fun accessibilityRole_switch() {
+ val stateSwitch =
+ QSTile.State().apply { expandedAccessibilityClassName = Switch::class.java.name }
+ val uiState = stateSwitch.toUiState()
+ assertThat(uiState.accessibilityRole).isEqualTo(Role.Switch)
+ }
+
+ @Test
+ fun accessibilityRole_button() {
+ val stateButton =
+ QSTile.State().apply { expandedAccessibilityClassName = Button::class.java.name }
+ val uiState = stateButton.toUiState()
+ assertThat(uiState.accessibilityRole).isEqualTo(Role.Button)
+ }
+
+ @Test
+ fun accessibilityRole_switchWithSecondaryClick() {
+ val stateSwitchWithSecondaryClick =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ handlesSecondaryClick = true
+ }
+ val uiState = stateSwitchWithSecondaryClick.toUiState()
+ assertThat(uiState.accessibilityRole).isEqualTo(Role.Button)
+ }
+
+ @Test
+ fun switchInactive_secondaryLabelNotModified() {
+ val testString = "TEST STRING"
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_INACTIVE
+ secondaryLabel = testString
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(testString)
+ }
+
+ @Test
+ fun switchActive_secondaryLabelNotModified() {
+ val testString = "TEST STRING"
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_ACTIVE
+ secondaryLabel = testString
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(testString)
+ }
+
+ @Test
+ fun buttonInactive_secondaryLabelNotModifiedWhenEmpty() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Button::class.java.name
+ state = Tile.STATE_INACTIVE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEmpty()
+ }
+
+ @Test
+ fun buttonActive_secondaryLabelNotModifiedWhenEmpty() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Button::class.java.name
+ state = Tile.STATE_ACTIVE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEmpty()
+ }
+
+ @Test
+ fun buttonUnavailable_emptySecondaryLabel_default() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Button::class.java.name
+ state = Tile.STATE_UNAVAILABLE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(resources.getString(R.string.tile_unavailable))
+ }
+
+ @Test
+ fun switchUnavailable_emptySecondaryLabel_defaultUnavailable() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_UNAVAILABLE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(resources.getString(R.string.tile_unavailable))
+ }
+
+ @Test
+ fun switchInactive_emptySecondaryLabel_defaultOff() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_INACTIVE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(resources.getString(R.string.switch_bar_off))
+ }
+
+ @Test
+ fun switchActive_emptySecondaryLabel_defaultOn() {
+ val state =
+ QSTile.State().apply {
+ expandedAccessibilityClassName = Switch::class.java.name
+ state = Tile.STATE_ACTIVE
+ secondaryLabel = ""
+ }
+
+ val uiState = state.toUiState()
+
+ assertThat(uiState.secondaryLabel).isEqualTo(resources.getString(R.string.switch_bar_on))
+ }
+
+ @Test
+ fun disabledByPolicy_inactive_appearsAsUnavailable() {
+ val stateDisabledByPolicy =
+ QSTile.State().apply {
+ state = Tile.STATE_INACTIVE
+ disabledByPolicy = true
+ }
+
+ val uiState = stateDisabledByPolicy.toUiState()
+
+ assertThat(uiState.state).isEqualTo(Tile.STATE_UNAVAILABLE)
+ }
+
+ @Test
+ fun disabledByPolicy_active_appearsAsUnavailable() {
+ val stateDisabledByPolicy =
+ QSTile.State().apply {
+ state = Tile.STATE_ACTIVE
+ disabledByPolicy = true
+ }
+
+ val uiState = stateDisabledByPolicy.toUiState()
+
+ assertThat(uiState.state).isEqualTo(Tile.STATE_UNAVAILABLE)
+ }
+
+ @Test
+ fun disabledByPolicy_clickLabel() {
+ val stateDisabledByPolicy =
+ QSTile.State().apply {
+ state = Tile.STATE_INACTIVE
+ disabledByPolicy = true
+ }
+
+ val uiState = stateDisabledByPolicy.toUiState()
+ assertThat(uiState.accessibilityUiState.clickLabel)
+ .isEqualTo(
+ resources.getString(
+ R.string.accessibility_tile_disabled_by_policy_action_description
+ )
+ )
+ }
+
+ @Test
+ fun notDisabledByPolicy_clickLabel_null() {
+ val stateDisabledByPolicy =
+ QSTile.State().apply {
+ state = Tile.STATE_INACTIVE
+ disabledByPolicy = false
+ }
+
+ val uiState = stateDisabledByPolicy.toUiState()
+ assertThat(uiState.accessibilityUiState.clickLabel).isNull()
+ }
+
+ @Test
+ fun disabledByPolicy_unavailableInStateDescription() {
+ val state =
+ QSTile.State().apply {
+ disabledByPolicy = true
+ state = Tile.STATE_INACTIVE
+ }
+
+ val uiState = state.toUiState()
+ assertThat(uiState.accessibilityUiState.stateDescription)
+ .contains(resources.getString(R.string.tile_unavailable))
+ }
+
+ private fun QSTile.State.toUiState() = toUiState(resources)
+}
+
+private val TileUiState.accessibilityRole: Role
+ get() = accessibilityUiState.accessibilityRole
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
index 762941d..fd1c043 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelTest.kt
@@ -21,6 +21,7 @@
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -28,6 +29,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -46,7 +48,7 @@
private val underTest = kosmos.quickSettingsShadeOverlayActionsViewModel
@Test
- fun upTransitionSceneKey_hidesShade() =
+ fun up_hidesShade() =
testScope.runTest {
val actions by collectLastValue(underTest.actions)
underTest.activateIn(this)
@@ -57,12 +59,44 @@
}
@Test
- fun back_hidesShade() =
+ fun back_notEditing_hidesShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ val isEditing by
+ collectLastValue(kosmos.quickSettingsContainerViewModel.editModeViewModel.isEditing)
+ underTest.activateIn(this)
+ assertThat(isEditing).isFalse()
+
+ assertThat((actions?.get(Back) as? UserActionResult.HideOverlay)?.overlay)
+ .isEqualTo(Overlays.QuickSettingsShade)
+ }
+
+ @Test
+ fun back_whileEditing_doesNotHideShade() =
testScope.runTest {
val actions by collectLastValue(underTest.actions)
underTest.activateIn(this)
- assertThat((actions?.get(Back) as? UserActionResult.HideOverlay)?.overlay)
- .isEqualTo(Overlays.QuickSettingsShade)
+ kosmos.quickSettingsContainerViewModel.editModeViewModel.startEditing()
+
+ assertThat(actions?.get(Back)).isNull()
+ }
+
+ @Test
+ fun downFromTopLeft_switchesToNotificationsShade() =
+ testScope.runTest {
+ val actions by collectLastValue(underTest.actions)
+ underTest.activateIn(this)
+
+ assertThat(
+ (actions?.get(
+ Swipe(
+ direction = SwipeDirection.Down,
+ fromSource = SceneContainerEdge.TopLeft,
+ )
+ ) as? UserActionResult.ReplaceByOverlay)
+ ?.overlay
+ )
+ .isEqualTo(Overlays.NotificationsShade)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
index 6986cf8e..62b6391 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsUserActionsViewModelTest.kt
@@ -37,7 +37,6 @@
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
-import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -46,7 +45,6 @@
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -61,7 +59,7 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
- private val qsFlexiglassAdapter = FakeQSSceneAdapter({ mock() })
+ private val qsFlexiglassAdapter = kosmos.fakeQsSceneAdapter
private val sceneInteractor = kosmos.sceneInteractor
private val sceneBackInteractor = kosmos.sceneBackInteractor
@@ -101,10 +99,8 @@
mapOf(
Back to UserActionResult(Scenes.Shade),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Gone)
@@ -130,10 +126,8 @@
mapOf(
Back to UserActionResult(Scenes.Lockscreen),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Lockscreen),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Lockscreen)
@@ -161,10 +155,8 @@
mapOf(
Back to UserActionResult(Scenes.Shade),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Gone)
@@ -187,10 +179,8 @@
mapOf(
Back to UserActionResult(Scenes.Shade),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Lockscreen)
@@ -225,10 +215,8 @@
mapOf(
Back to UserActionResult(Scenes.Shade),
Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade),
- Swipe(
- fromSource = Edge.Bottom,
- direction = SwipeDirection.Up,
- ) to UserActionResult(SceneFamilies.Home)
+ Swipe(fromSource = Edge.Bottom, direction = SwipeDirection.Up) to
+ UserActionResult(SceneFamilies.Home),
)
)
assertThat(homeScene).isEqualTo(Scenes.Gone)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
index edaa3d3..bf97afe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt
@@ -18,9 +18,12 @@
package com.android.systemui.scene.domain.interactor
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.ObservableTransitionState.Transition.ShowOrHideOverlay
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -29,8 +32,10 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.sceneDataSource
+import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
@@ -63,10 +68,11 @@
private val sceneDataSource =
kosmos.sceneDataSource.apply { changeScene(toScene = Scenes.Lockscreen) }
- private val underTest = kosmos.sceneContainerOcclusionInteractor
+ private val underTest by lazy { kosmos.sceneContainerOcclusionInteractor }
@Test
- fun invisibleDueToOcclusion() =
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun invisibleDueToOcclusion_dualShadeDisabled() =
testScope.runTest {
val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion)
val keyguardState by collectLastValue(keyguardTransitionInteractor.currentKeyguardState)
@@ -126,6 +132,68 @@
.isFalse()
}
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun invisibleDueToOcclusion_dualShadeEnabled() =
+ testScope.runTest {
+ val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion)
+ val keyguardState by collectLastValue(keyguardTransitionInteractor.currentKeyguardState)
+
+ // Assert that we have the desired preconditions:
+ assertThat(keyguardState).isEqualTo(KeyguardState.LOCKSCREEN)
+ assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen)
+ assertThat(sceneInteractor.transitionState.value)
+ .isEqualTo(ObservableTransitionState.Idle(Scenes.Lockscreen))
+ assertWithMessage("Should start unoccluded").that(invisibleDueToOcclusion).isFalse()
+
+ // Actual testing starts here:
+ showOccludingActivity()
+ assertWithMessage("Should become occluded when occluding activity is shown")
+ .that(invisibleDueToOcclusion)
+ .isTrue()
+
+ transitionIntoAod {
+ assertWithMessage("Should become unoccluded when transitioning into AOD")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+ assertWithMessage("Should stay unoccluded when in AOD")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+
+ transitionOutOfAod {
+ assertWithMessage("Should remain unoccluded while transitioning away from AOD")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+ assertWithMessage("Should become occluded now that no longer in AOD")
+ .that(invisibleDueToOcclusion)
+ .isTrue()
+
+ expandDualShade {
+ assertWithMessage("Should become unoccluded once shade begins to expand")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+ assertWithMessage("Should be unoccluded when shade is fully expanded")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+
+ collapseDualShade {
+ assertWithMessage("Should remain unoccluded while shade is collapsing")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+ assertWithMessage("Should become occluded now that shade is fully collapsed")
+ .that(invisibleDueToOcclusion)
+ .isTrue()
+
+ hideOccludingActivity()
+ assertWithMessage("Should become unoccluded once the occluding activity is hidden")
+ .that(invisibleDueToOcclusion)
+ .isFalse()
+ }
+
/** Simulates the appearance of a show-when-locked `Activity` in the foreground. */
private fun TestScope.showOccludingActivity() {
keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
@@ -138,15 +206,13 @@
/** Simulates the disappearance of a show-when-locked `Activity` from the foreground. */
private fun TestScope.hideOccludingActivity() {
keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(
- showWhenLockedActivityOnTop = false,
+ showWhenLockedActivityOnTop = false
)
runCurrent()
}
/** Simulates a user-driven gradual expansion of the shade. */
- private fun TestScope.expandShade(
- assertMidTransition: () -> Unit = {},
- ) {
+ private fun TestScope.expandShade(assertMidTransition: () -> Unit = {}) {
val progress = MutableStateFlow(0f)
mutableTransitionState.value =
ObservableTransitionState.Transition(
@@ -170,10 +236,41 @@
runCurrent()
}
+ /** Simulates a user-driven gradual expansion of the dual shade (notifications). */
+ private fun TestScope.expandDualShade(assertMidTransition: () -> Unit = {}) {
+ val progress = MutableStateFlow(0f)
+ mutableTransitionState.value =
+ ShowOrHideOverlay(
+ overlay = Overlays.NotificationsShade,
+ fromContent = sceneDataSource.currentScene.value,
+ toContent = Overlays.NotificationsShade,
+ currentScene = sceneDataSource.currentScene.value,
+ currentOverlays = sceneDataSource.currentOverlays,
+ progress = progress,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ runCurrent()
+
+ progress.value = 0.5f
+ runCurrent()
+ assertMidTransition()
+
+ progress.value = 1f
+ runCurrent()
+
+ mutableTransitionState.value =
+ ObservableTransitionState.Idle(
+ sceneDataSource.currentScene.value,
+ setOf(Overlays.NotificationsShade),
+ )
+ runCurrent()
+ }
+
/** Simulates a user-driven gradual collapse of the shade. */
- private fun TestScope.collapseShade(
- assertMidTransition: () -> Unit = {},
- ) {
+ private fun TestScope.collapseShade(assertMidTransition: () -> Unit = {}) {
val progress = MutableStateFlow(0f)
mutableTransitionState.value =
ObservableTransitionState.Transition(
@@ -197,10 +294,37 @@
runCurrent()
}
+ /** Simulates a user-driven gradual collapse of the dual shade (notifications). */
+ private fun TestScope.collapseDualShade(assertMidTransition: () -> Unit = {}) {
+ val progress = MutableStateFlow(0f)
+ mutableTransitionState.value =
+ ShowOrHideOverlay(
+ overlay = Overlays.NotificationsShade,
+ fromContent = Overlays.NotificationsShade,
+ toContent = Scenes.Lockscreen,
+ currentScene = Scenes.Lockscreen,
+ currentOverlays = flowOf(setOf(Overlays.NotificationsShade)),
+ progress = progress,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ runCurrent()
+
+ progress.value = 0.5f
+ runCurrent()
+ assertMidTransition()
+
+ progress.value = 1f
+ runCurrent()
+
+ mutableTransitionState.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+ runCurrent()
+ }
+
/** Simulates a transition into AOD. */
- private suspend fun TestScope.transitionIntoAod(
- assertMidTransition: () -> Unit = {},
- ) {
+ private suspend fun TestScope.transitionIntoAod(assertMidTransition: () -> Unit = {}) {
val currentKeyguardState = keyguardTransitionInteractor.getCurrentState()
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -235,9 +359,7 @@
}
/** Simulates a transition away from AOD. */
- private suspend fun TestScope.transitionOutOfAod(
- assertMidTransition: () -> Unit = {},
- ) {
+ private suspend fun TestScope.transitionOutOfAod(assertMidTransition: () -> Unit = {}) {
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
from = KeyguardState.AOD,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 4a7d8b0..7fe3d8d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -21,6 +21,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.ObservableTransitionState.Transition.ShowOrHideOverlay
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -38,6 +39,7 @@
import com.android.systemui.scene.overlayKeys
import com.android.systemui.scene.sceneContainerConfig
import com.android.systemui.scene.sceneKeys
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
@@ -256,7 +258,7 @@
}
@Test
- fun transitioningTo() =
+ fun transitioningTo_sceneChange() =
testScope.runTest {
val transitionState =
MutableStateFlow<ObservableTransitionState>(
@@ -293,6 +295,51 @@
}
@Test
+ fun transitioningTo_overlayChange() =
+ testScope.runTest {
+ val transitionState =
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(underTest.currentScene.value)
+ )
+ underTest.setTransitionState(transitionState)
+
+ val transitionTo by collectLastValue(underTest.transitioningTo)
+ assertThat(transitionTo).isNull()
+
+ underTest.showOverlay(Overlays.NotificationsShade, "reason")
+ assertThat(transitionTo).isNull()
+
+ val progress = MutableStateFlow(0f)
+ transitionState.value =
+ ShowOrHideOverlay(
+ overlay = Overlays.NotificationsShade,
+ fromContent = underTest.currentScene.value,
+ toContent = Overlays.NotificationsShade,
+ currentScene = underTest.currentScene.value,
+ currentOverlays = underTest.currentOverlays,
+ progress = progress,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ assertThat(transitionTo).isEqualTo(Overlays.NotificationsShade)
+
+ progress.value = 0.5f
+ assertThat(transitionTo).isEqualTo(Overlays.NotificationsShade)
+
+ progress.value = 1f
+ assertThat(transitionTo).isEqualTo(Overlays.NotificationsShade)
+
+ transitionState.value =
+ ObservableTransitionState.Idle(
+ currentScene = underTest.currentScene.value,
+ currentOverlays = setOf(Overlays.NotificationsShade),
+ )
+ assertThat(transitionTo).isNull()
+ }
+
+ @Test
fun isTransitionUserInputOngoing_idle_false() =
testScope.runTest {
val transitionState =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 763a1a9..3850891 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -27,6 +27,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.uiEventLoggerFake
import com.android.internal.policy.IKeyguardDismissCallback
@@ -88,9 +89,11 @@
import com.android.systemui.scene.data.repository.Transition
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shared.system.QuickStepContract
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
@@ -161,6 +164,7 @@
}
@Test
+ @DisableFlags(DualShade.FLAG_NAME)
fun hydrateVisibility() =
testScope.runTest {
val currentDesiredSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -221,6 +225,87 @@
}
@Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun hydrateVisibility_dualShade() =
+ testScope.runTest {
+ val currentDesiredSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val currentDesiredOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ val isVisible by collectLastValue(sceneInteractor.isVisible)
+ val transitionStateFlow =
+ prepareState(
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ isDeviceUnlocked = true,
+ initialSceneKey = Scenes.Gone,
+ )
+ assertThat(currentDesiredSceneKey).isEqualTo(Scenes.Gone)
+ assertThat(currentDesiredOverlays).isEmpty()
+ assertThat(isVisible).isTrue()
+
+ underTest.start()
+ assertThat(isVisible).isFalse()
+
+ // Expand the notifications shade.
+ fakeSceneDataSource.pause()
+ sceneInteractor.showOverlay(Overlays.NotificationsShade, "reason")
+ transitionStateFlow.value =
+ ObservableTransitionState.Transition.ShowOrHideOverlay(
+ overlay = Overlays.NotificationsShade,
+ fromContent = Scenes.Gone,
+ toContent = Overlays.NotificationsShade,
+ currentScene = Scenes.Gone,
+ currentOverlays = flowOf(emptySet()),
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ assertThat(isVisible).isTrue()
+ fakeSceneDataSource.unpause(expectedScene = Scenes.Gone)
+ transitionStateFlow.value =
+ ObservableTransitionState.Idle(
+ currentScene = Scenes.Gone,
+ currentOverlays = setOf(Overlays.NotificationsShade),
+ )
+ assertThat(isVisible).isTrue()
+
+ // Collapse the notifications shade.
+ fakeSceneDataSource.pause()
+ sceneInteractor.hideOverlay(Overlays.NotificationsShade, "reason")
+ transitionStateFlow.value =
+ ObservableTransitionState.Transition.ShowOrHideOverlay(
+ overlay = Overlays.NotificationsShade,
+ fromContent = Overlays.NotificationsShade,
+ toContent = Scenes.Gone,
+ currentScene = Scenes.Gone,
+ currentOverlays = flowOf(setOf(Overlays.NotificationsShade)),
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = false,
+ isUserInputOngoing = flowOf(false),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ assertThat(isVisible).isTrue()
+ fakeSceneDataSource.unpause(expectedScene = Scenes.Gone)
+ transitionStateFlow.value =
+ ObservableTransitionState.Idle(
+ currentScene = Scenes.Gone,
+ currentOverlays = emptySet(),
+ )
+ assertThat(isVisible).isFalse()
+
+ kosmos.headsUpNotificationRepository.setNotifications(
+ buildNotificationRows(isPinned = true)
+ )
+ assertThat(isVisible).isTrue()
+
+ kosmos.headsUpNotificationRepository.setNotifications(
+ buildNotificationRows(isPinned = false)
+ )
+ assertThat(isVisible).isFalse()
+ }
+
+ @Test
fun hydrateVisibility_basedOnDeviceProvisioning() =
testScope.runTest {
val isVisible by collectLastValue(sceneInteractor.isVisible)
@@ -1621,6 +1706,7 @@
}
@Test
+ @DisableFlags(DualShade.FLAG_NAME)
fun hydrateInteractionState_whileLocked() =
testScope.runTest {
val transitionStateFlow = prepareState(initialSceneKey = Scenes.Lockscreen)
@@ -1707,6 +1793,7 @@
}
@Test
+ @DisableFlags(DualShade.FLAG_NAME)
fun hydrateInteractionState_whileUnlocked() =
testScope.runTest {
val transitionStateFlow =
@@ -1795,6 +1882,186 @@
}
@Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun hydrateInteractionState_dualShade_whileLocked() =
+ testScope.runTest {
+ val currentDesiredOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ val transitionStateFlow = prepareState(initialSceneKey = Scenes.Lockscreen)
+ underTest.start()
+ runCurrent()
+ verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
+ assertThat(currentDesiredOverlays).isEmpty()
+
+ clearInvocations(centralSurfaces)
+ emulateSceneTransition(
+ transitionStateFlow = transitionStateFlow,
+ toScene = Scenes.Bouncer,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces)
+ .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false)
+ },
+ )
+
+ clearInvocations(centralSurfaces)
+ emulateSceneTransition(
+ transitionStateFlow = transitionStateFlow,
+ toScene = Scenes.Lockscreen,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
+ },
+ )
+
+ clearInvocations(centralSurfaces)
+ emulateOverlayTransition(
+ transitionStateFlow = transitionStateFlow,
+ toOverlay = Overlays.NotificationsShade,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces)
+ .setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false)
+ },
+ )
+
+ clearInvocations(centralSurfaces)
+ emulateSceneTransition(
+ transitionStateFlow = transitionStateFlow,
+ toScene = Scenes.Lockscreen,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces).setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true)
+ },
+ )
+
+ clearInvocations(centralSurfaces)
+ emulateOverlayTransition(
+ transitionStateFlow = transitionStateFlow,
+ toOverlay = Overlays.QuickSettingsShade,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ )
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun hydrateInteractionState_dualShade_whileUnlocked() =
+ testScope.runTest {
+ val currentDesiredOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ val transitionStateFlow =
+ prepareState(
+ authenticationMethod = AuthenticationMethodModel.Pin,
+ isDeviceUnlocked = true,
+ initialSceneKey = Scenes.Gone,
+ )
+ underTest.start()
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ assertThat(currentDesiredOverlays).isEmpty()
+
+ clearInvocations(centralSurfaces)
+ emulateSceneTransition(
+ transitionStateFlow = transitionStateFlow,
+ toScene = Scenes.Bouncer,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ )
+
+ clearInvocations(centralSurfaces)
+ emulateSceneTransition(
+ transitionStateFlow = transitionStateFlow,
+ toScene = Scenes.Lockscreen,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ )
+
+ clearInvocations(centralSurfaces)
+ emulateSceneTransition(
+ transitionStateFlow = transitionStateFlow,
+ toScene = Scenes.Shade,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ )
+
+ clearInvocations(centralSurfaces)
+ emulateSceneTransition(
+ transitionStateFlow = transitionStateFlow,
+ toScene = Scenes.Lockscreen,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ )
+
+ clearInvocations(centralSurfaces)
+ emulateSceneTransition(
+ transitionStateFlow = transitionStateFlow,
+ toScene = Scenes.QuickSettings,
+ verifyBeforeTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyDuringTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ verifyAfterTransition = {
+ verify(centralSurfaces, never()).setInteracting(anyInt(), anyBoolean())
+ },
+ )
+ }
+
+ @Test
fun respondToFalsingDetections() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
@@ -2131,19 +2398,40 @@
verifyAfterTransition: (() -> Unit)? = null,
) {
val fromScene = sceneInteractor.currentScene.value
+ val fromOverlays = sceneInteractor.currentOverlays.value
sceneInteractor.changeScene(toScene, "reason")
runCurrent()
verifyBeforeTransition?.invoke()
transitionStateFlow.value =
- ObservableTransitionState.Transition(
- fromScene = fromScene,
- toScene = toScene,
- currentScene = flowOf(fromScene),
- progress = flowOf(0.5f),
- isInitiatedByUserInput = true,
- isUserInputOngoing = flowOf(true),
- )
+ if (fromOverlays.isEmpty()) {
+ // Regular scene-to-scene transition.
+ ObservableTransitionState.Transition.ChangeScene(
+ fromScene = fromScene,
+ toScene = toScene,
+ currentScene = flowOf(fromScene),
+ currentOverlays = fromOverlays,
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ } else {
+ // An overlay is present; hide it.
+ ObservableTransitionState.Transition.ShowOrHideOverlay(
+ overlay = fromOverlays.first(),
+ fromContent = fromOverlays.first(),
+ toContent = toScene,
+ currentScene = fromScene,
+ currentOverlays = sceneInteractor.currentOverlays,
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ }
runCurrent()
verifyDuringTransition?.invoke()
@@ -2152,6 +2440,60 @@
verifyAfterTransition?.invoke()
}
+ private fun TestScope.emulateOverlayTransition(
+ transitionStateFlow: MutableStateFlow<ObservableTransitionState>,
+ toOverlay: OverlayKey,
+ verifyBeforeTransition: (() -> Unit)? = null,
+ verifyDuringTransition: (() -> Unit)? = null,
+ verifyAfterTransition: (() -> Unit)? = null,
+ ) {
+ val fromScene = sceneInteractor.currentScene.value
+ val fromOverlays = sceneInteractor.currentOverlays.value
+ sceneInteractor.showOverlay(toOverlay, "reason")
+ runCurrent()
+ verifyBeforeTransition?.invoke()
+
+ transitionStateFlow.value =
+ if (fromOverlays.isEmpty()) {
+ // Show a new overlay.
+ ObservableTransitionState.Transition.ShowOrHideOverlay(
+ overlay = toOverlay,
+ fromContent = fromScene,
+ toContent = toOverlay,
+ currentScene = fromScene,
+ currentOverlays = sceneInteractor.currentOverlays,
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ } else {
+ // Overlay-to-overlay transition.
+ ObservableTransitionState.Transition.ReplaceOverlay(
+ fromOverlay = fromOverlays.first(),
+ toOverlay = toOverlay,
+ currentScene = fromScene,
+ currentOverlays = sceneInteractor.currentOverlays,
+ progress = flowOf(0.5f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ }
+ runCurrent()
+ verifyDuringTransition?.invoke()
+
+ transitionStateFlow.value =
+ ObservableTransitionState.Idle(
+ currentScene = fromScene,
+ currentOverlays = setOf(toOverlay),
+ )
+ runCurrent()
+ verifyAfterTransition?.invoke()
+ }
+
private fun TestScope.prepareState(
isDeviceUnlocked: Boolean = false,
isBypassEnabled: Boolean = false,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt
index 4d69f0d..f86337e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt
@@ -19,8 +19,8 @@
import android.platform.test.flag.junit.FlagsParameterization
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_COMPOSE_LOCKSCREEN
import com.android.systemui.Flags.FLAG_EXAMPLE_FLAG
+import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.andSceneContainer
@@ -66,7 +66,7 @@
@Test
fun oneDependencyAndSceneContainer() {
- val dependentFlag = FLAG_COMPOSE_LOCKSCREEN
+ val dependentFlag = FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
val result = FlagsParameterization.allCombinationsOf(dependentFlag).andSceneContainer()
Truth.assertThat(result).hasSize(3)
Truth.assertThat(result[0].mOverrides[dependentFlag]).isFalse()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
index e6a24e3..5c47f55 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
@@ -21,13 +21,17 @@
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.shade.domain.interactor.shadeInteractor
@@ -92,4 +96,42 @@
assertThat(userActions?.get(Swipe(SwipeDirection.Down))?.transitionKey).isNull()
}
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun swipeDownWithTwoFingers_singleShade_goesToQuickSettings() =
+ testScope.runTest {
+ val userActions by collectLastValue(underTest.actions)
+ shadeRepository.setShadeLayoutWide(false)
+ runCurrent()
+
+ assertThat(userActions?.get(swipeDownFromTopWithTwoFingers()))
+ .isEqualTo(UserActionResult(Scenes.QuickSettings))
+ }
+
+ @Test
+ @DisableFlags(DualShade.FLAG_NAME)
+ fun swipeDownWithTwoFingers_splitShade_goesToShade() =
+ testScope.runTest {
+ val userActions by collectLastValue(underTest.actions)
+ shadeRepository.setShadeLayoutWide(true)
+ runCurrent()
+
+ assertThat(userActions?.get(swipeDownFromTopWithTwoFingers()))
+ .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
+ }
+
+ @Test
+ @EnableFlags(DualShade.FLAG_NAME)
+ fun swipeDownWithTwoFingers_dualShadeEnabled_isNull() =
+ testScope.runTest {
+ val userActions by collectLastValue(underTest.actions)
+ runCurrent()
+
+ assertThat(userActions?.get(swipeDownFromTopWithTwoFingers())).isNull()
+ }
+
+ private fun swipeDownFromTopWithTwoFingers(): UserAction {
+ return Swipe(direction = SwipeDirection.Down, pointerCount = 2, fromSource = Edge.Top)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
index 851b7b9..ba559b5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
@@ -21,6 +21,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.ObservableTransitionState.Transition.ShowOrHideOverlay
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -32,6 +34,7 @@
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.testKosmos
@@ -125,6 +128,63 @@
@Test
@EnableSceneContainer
+ fun legacyPanelExpansion_dualShade_whenIdle_whenLocked() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+ changeScene(Scenes.Lockscreen) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ changeScene(Scenes.Bouncer) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ showOverlay(Overlays.NotificationsShade) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ showOverlay(Overlays.QuickSettingsShade) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+ }
+
+ @Test
+ @EnableSceneContainer
+ fun legacyPanelExpansion_dualShade_whenIdle_whenUnlocked() =
+ testScope.runTest {
+ underTest = kosmos.panelExpansionInteractorImpl
+ val unlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus)
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ runCurrent()
+
+ assertThat(unlockStatus)
+ .isEqualTo(DeviceUnlockStatus(true, DeviceUnlockSource.Fingerprint))
+
+ val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+ changeScene(Scenes.Gone) { assertThat(panelExpansion).isEqualTo(0f) }
+ assertThat(panelExpansion).isEqualTo(0f)
+
+ showOverlay(Overlays.NotificationsShade) { progress ->
+ assertThat(panelExpansion).isEqualTo(progress)
+ }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ showOverlay(Overlays.QuickSettingsShade) {
+ // Notification shade is already expanded, so moving to QS shade should also be 1f.
+ assertThat(panelExpansion).isEqualTo(1f)
+ }
+ assertThat(panelExpansion).isEqualTo(1f)
+
+ changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
+ assertThat(panelExpansion).isEqualTo(1f)
+ }
+
+ @Test
+ @EnableSceneContainer
fun shouldHideStatusBarIconsWhenExpanded_goneScene() =
testScope.runTest {
underTest = kosmos.panelExpansionInteractorImpl
@@ -193,4 +253,72 @@
assertThat(currentScene).isEqualTo(toScene)
}
+
+ private fun TestScope.showOverlay(
+ toOverlay: OverlayKey,
+ assertDuringProgress: ((progress: Float) -> Unit) = {},
+ ) {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ val progressFlow = MutableStateFlow(0f)
+ transitionState.value =
+ if (checkNotNull(currentOverlays).isEmpty()) {
+ ShowOrHideOverlay(
+ overlay = toOverlay,
+ fromContent = checkNotNull(currentScene),
+ toContent = toOverlay,
+ currentScene = checkNotNull(currentScene),
+ currentOverlays = flowOf(emptySet()),
+ progress = progressFlow,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ } else {
+ ObservableTransitionState.Transition.ReplaceOverlay(
+ fromOverlay = checkNotNull(currentOverlays).first(),
+ toOverlay = toOverlay,
+ currentScene = checkNotNull(currentScene),
+ currentOverlays = flowOf(emptySet()),
+ progress = progressFlow,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ previewProgress = flowOf(0f),
+ isInPreviewStage = flowOf(false),
+ )
+ }
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 0.2f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 0.6f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ progressFlow.value = 1f
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ transitionState.value =
+ ObservableTransitionState.Idle(
+ currentScene = checkNotNull(currentScene),
+ currentOverlays = setOf(toOverlay),
+ )
+ if (checkNotNull(currentOverlays).isEmpty()) {
+ fakeSceneDataSource.showOverlay(toOverlay)
+ } else {
+ fakeSceneDataSource.replaceOverlay(
+ from = checkNotNull(currentOverlays).first(),
+ to = toOverlay,
+ )
+ }
+ runCurrent()
+ assertDuringProgress(progressFlow.value)
+
+ assertThat(currentOverlays).containsExactly(toOverlay)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/telephony/TelephonyCallbackTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyCallbackTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/telephony/TelephonyCallbackTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/telephony/TelephonyListenerManagerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TemporaryViewLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewUiEventLoggerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TemporaryViewUiEventLoggerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewUiEventLoggerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/temporarydisplay/TemporaryViewUiEventLoggerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/data/repository/TouchpadRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/data/repository/TouchpadRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/data/repository/TouchpadRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/data/repository/TouchpadRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/BackGestureMonitorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/FakeMotionEvent.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/FakeMotionEvent.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/FakeMotionEvent.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/FakeMotionEvent.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/HomeGestureMonitorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/RecentAppsGestureMonitorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureBuilder.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureBuilder.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureBuilder.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureBuilder.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureBuilderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureBuilderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureBuilderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureBuilderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/TouchpadGestureHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/tracing/TraceUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/tracing/TraceUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/tracing/TraceUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/tracing/TraceUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimationTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldStateRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/FoldStateRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldHapticsPlayerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTestUtilsKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldTestUtilsKosmos.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTestUtilsKosmos.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldTestUtilsKosmos.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/config/TestUnfoldTransitionConfig.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/config/TestUnfoldTransitionConfig.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/config/TestUnfoldTransitionConfig.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/config/TestUnfoldTransitionConfig.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/MainThreadUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/MainThreadUnfoldTransitionProgressProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/progress/MainThreadUnfoldTransitionProgressProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/MainThreadUnfoldTransitionProgressProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/RemoteUnfoldTransitionReceiverTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/progress/TestUnfoldProgressListener.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/DeviceStateRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
similarity index 85%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index f5bcc21..feee0a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -38,6 +38,7 @@
import org.mockito.Mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
+import org.mockito.Mockito.inOrder
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
@@ -79,6 +80,26 @@
}
@Test
+ fun onRotationChanged_rotationSentMultipleWithTheSameValue_listenerReceivesUpdateOnce() {
+ sendRotationUpdate(42)
+ sendRotationUpdate(42)
+ sendRotationUpdate(42)
+
+ verify(listener).onRotationChanged(42)
+ }
+
+ @Test
+ fun onRotationChanged_rotationSentMultipleTimesWithDifferentValues_listenerReceivesUpdates() {
+ sendRotationUpdate(0)
+ sendRotationUpdate(1)
+
+ with(inOrder(listener)) {
+ verify(listener).onRotationChanged(0)
+ verify(listener).onRotationChanged(1)
+ }
+ }
+
+ @Test
fun onRotationChanged_subscribersRemoved_noRotationChangeReceived() {
sendRotationUpdate(42)
verify(listener).onRotationChanged(42)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldProvider.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/TestFoldProvider.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldProvider.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/TestFoldProvider.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/UnfoldOnlyProgressProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/UnfoldOnlyProgressProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/unfold/util/UnfoldOnlyProgressProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/util/UnfoldOnlyProgressProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/DeviceConfigProxyFakeTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/WallpaperControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/WallpaperControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/concurrency/FakeExecutorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/concurrency/RepeatableExecutorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/LoopedAnimatable2DrawableWrapperTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/icons/AppCategoryIconProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/icons/AppCategoryIconProviderTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/icons/AppCategoryIconProviderTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/icons/AppCategoryIconProviderTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowProvider.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/FlowProvider.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakReporterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/LeakReporterTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakReporterTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/leak/LeakReporterTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ref/GcWeakReference.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/ref/GcWeakReference.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/ref/GcWeakReference.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/ref/GcWeakReference.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/service/PackageObserverTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/service/PackageObserverTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/service/PackageObserverTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/FakeSettingsTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettingsTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/FakeSettingsTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/repository/UserAwareSecureSettingsRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/ui/AnimatedValueTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/view/ViewUtilTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/view/ViewUtilTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/WakeLockTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/WakeLockTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeControllerAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeControllerAdapterTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/VolumeControllerAdapterTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/VolumeControllerAdapterTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/data/repository/VolumeDialogRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/data/repository/VolumeDialogRepositoryTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/data/repository/VolumeDialogRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/data/repository/VolumeDialogRepositoryTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/domain/interactor/VolumeDialogInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/VolumeDialogInteractorTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/volume/domain/interactor/VolumeDialogInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/VolumeDialogInteractorTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualLocationsServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallet/controller/WalletContextualLocationsServiceTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualLocationsServiceTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wallet/controller/WalletContextualLocationsServiceTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractorTest.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/WallpaperLocalColorExtractorTest.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubblesTestActivity.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/BubblesTestActivity.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/SyncExecutor.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wmshell/SyncExecutor.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/SyncExecutor.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubblePositioner.java
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubblePositioner.java
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index 4812ff0..8dc4815 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -69,11 +69,7 @@
val events: ClockEvents
/** Initializes various rendering parameters. If never called, provides reasonable defaults. */
- fun initialize(
- resources: Resources,
- dozeFraction: Float,
- foldFraction: Float,
- )
+ fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float)
/** Optional method for dumping debug information */
fun dump(pw: PrintWriter)
@@ -109,11 +105,7 @@
val largeClockMessageBuffer: MessageBuffer,
)
-data class AodClockBurnInModel(
- val scale: Float,
- val translationX: Float,
- val translationY: Float,
-)
+data class AodClockBurnInModel(val scale: Float, val translationX: Float, val translationY: Float)
/** Specifies layout information for the */
interface ClockFaceLayout {
@@ -180,8 +172,20 @@
/** Call with zen/dnd information */
fun onZenDataChanged(data: ZenData)
+
+ /** Update reactive axes for this clock */
+ fun onReactiveAxesChanged(axes: List<ClockReactiveSetting>)
}
+/** Axis setting value for a clock */
+data class ClockReactiveSetting(
+ /** Axis key; matches ClockReactiveAxis.key */
+ val key: String,
+
+ /** Value to set this axis to */
+ val value: Float,
+)
+
/** Methods which trigger various clock animations */
interface ClockAnimations {
/** Runs an enter animation (if any) */
@@ -264,9 +268,7 @@
}
/** Some data about a clock design */
-data class ClockMetadata(
- val clockId: ClockId,
-)
+data class ClockMetadata(val clockId: ClockId)
data class ClockPickerConfig(
val id: String,
@@ -283,10 +285,46 @@
/** True if the clock will react to tone changes in the seed color */
val isReactiveToTone: Boolean = true,
- /** True if the clock is capable of chagning style in reaction to touches */
+ /** True if the clock is capable of changing style in reaction to touches */
val isReactiveToTouch: Boolean = false,
+
+ /** Font axes that can be modified on this clock */
+ val axes: List<ClockReactiveAxis> = listOf(),
)
+/** Represents an Axis that can be modified */
+data class ClockReactiveAxis(
+ /** Axis key, not user renderable */
+ val key: String,
+
+ /** Intended mode of user interaction */
+ val type: AxisType,
+
+ /** Maximum value the axis supports */
+ val maxValue: Float,
+
+ /** Minimum value the axis supports */
+ val minValue: Float,
+
+ /** Current value the axis is set to */
+ val currentValue: Float,
+
+ /** User-renderable name of the axis */
+ val name: String,
+
+ /** Description of the axis */
+ val description: String,
+)
+
+/** Axis user interaction modes */
+enum class AxisType {
+ /** Boolean toggle. Swaps between minValue & maxValue */
+ Toggle,
+
+ /** Continuous slider between minValue & maxValue */
+ Slider,
+}
+
/** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
data class ClockConfig(
val id: String,
@@ -300,7 +338,8 @@
/** Transition to AOD should move smartspace like large clock instead of small clock */
val useAlternateSmartspaceAODTransition: Boolean = false,
- @Deprecated("TODO(b/352049256): Remove")
+ /** Use ClockPickerConfig.isReactiveToTone instead */
+ @Deprecated("TODO(b/352049256): Remove in favor of ClockPickerConfig.isReactiveToTone")
val isReactiveToTone: Boolean = true,
/** True if the clock is large frame clock, which will use weather in compose. */
@@ -331,6 +370,7 @@
data class ClockSettings(
val clockId: ClockId? = null,
val seedColor: Int? = null,
+ val axes: List<ClockReactiveSetting>? = null,
) {
// Exclude metadata from equality checks
var metadata: JSONObject = JSONObject()
@@ -345,6 +385,8 @@
return ""
}
+ // TODO(b/364673977): Serialize axes
+
return JSONObject()
.put(KEY_CLOCK_ID, setting.clockId)
.put(KEY_SEED_COLOR, setting.seedColor)
@@ -357,11 +399,13 @@
return null
}
+ // TODO(b/364673977): Deserialize axes
+
val json = JSONObject(jsonStr)
val result =
ClockSettings(
if (!json.isNull(KEY_CLOCK_ID)) json.getString(KEY_CLOCK_ID) else null,
- if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null
+ if (!json.isNull(KEY_SEED_COLOR)) json.getInt(KEY_SEED_COLOR) else null,
)
if (!json.isNull(KEY_METADATA)) {
result.metadata = json.getJSONObject(KEY_METADATA)
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
index 6c8db91..84f7a51 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
@@ -28,4 +28,8 @@
<!-- Overload default clock widget parameters -->
<dimen name="widget_big_font_size">100dp</dimen>
<dimen name="widget_label_font_size">18sp</dimen>
+
+ <!-- New keyboard shortcut helper -->
+ <dimen name="shortcut_helper_width">704dp</dimen>
+ <dimen name="shortcut_helper_height">1208dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml b/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml
index 06d1bf4..a15532f 100644
--- a/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml
+++ b/packages/SystemUI/res/layout/activity_keyboard_shortcut_helper.xml
@@ -2,14 +2,15 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/shortcut_helper_sheet_container"
+ android:layout_gravity="center_horizontal|bottom"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/shortcut_helper_sheet"
style="@style/ShortcutHelperBottomSheet"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="@dimen/shortcut_helper_width"
+ android:layout_height="@dimen/shortcut_helper_height"
android:orientation="vertical"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 0fb0aaf..900c11e 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Voeg by nota"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Sluit skakel in"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Skakels kan nie vanaf jou ander profiele bygevoeg word nie"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skermopnemer"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Verwerk tans skermopname"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Deurlopende kennisgewing vir \'n skermopnamesessie"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Voeg by"</string>
<string name="manage_users" msgid="1823875311934643849">"Bestuur gebruikers"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Sleep na verdeelde skerm word nie vir hierdie kennisgewing gesteun nie"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑fi onbeskikbaar"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteitmodus"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gestel"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Pasmaak sluitskerm"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ontsluit om sluitskerm te pasmaak"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-fi is nie beskikbaar nie"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera is geblokkeer"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera en mikrofoon is geblokkeer"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoon is geblokkeer"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Leer raakpaneelgebare, kortpadsleutels en meer"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Teruggebaar"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Tuisgebaar"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Handelingsleutel"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gaan terug"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Swiep enige plek op die raakpaneel links of regs met drie vingers om terug te gaan.\n\nJy kan ook die kortpadsleutelhandeling + Esc hiervoor gebruik."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Swiep enige tyd van die onderkant van jou skerm af op met drie vingers om na jou tuisskerm toe te gaan."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Mooi so!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Jy het die Gaan na Tuisskerm-gebaar voltooi."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Handelingsleutel"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Druk die handelingsleutel op jou sleutelbord om toegang tot jou apps te kry."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Geluk!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Swiep op en hou met drie vingers. Tik om meer gebare te leer."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gebruik jou sleutelbord om alle apps te bekyk"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Druk enige tyd die handelingsleutel. Tik om meer gebare te leer."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Ekstra donker is nou deel van die helderheidbalk"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Jy kan nou die skerm ekstra donker maak deur die helderheidvlak vanaf die bokant van jou skerm nog laer te maak.\n\nDit werk die beste wanneer jy in ’n donker omgewing is."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Verwyder kortpad vir ekstra donker"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Kortpad vir ekstra donker is verwyder. Gebruik die gewone helderheidbalk om jou helderheid te verlaag."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Konnektiwiteit"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Toeganklikheid"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Nutsdienste"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privaatheid"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Verskaf deur apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Vertoon"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Onbekend"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 286acea..6a68dd9 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"አክል"</string>
<string name="manage_users" msgid="1823875311934643849">"ተጠቃሚዎችን ያስተዳድሩ"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ይህ ማሳወቂያ ወደ የተከፈለ ማያ ገፅ መጎተትን አይደግፍም"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi አይገኝም"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"የቅድሚያ ሁነታ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ማንቂያ ተቀናብሯል"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ማያ ገፅ ቁልፍን አብጅ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"የማያ ገጽ ቁልፍን ለማበጀት ይክፈቱ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi አይገኝም"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ካሜራ ታግዷል"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ካሜራ እና ማይክሮፎን ታግደዋል"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ማይክሮፎን ታግዷል"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"የመዳሰሻ ሰሌዳ ምልክቶችን፣ የቁልፍ ሰሌዳ አቋራጮችን እና ሌሎችን ይወቁ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"የተመለስ ምልክት"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"የቤት ምልክት"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"የተግባር ቁልፍ"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ተከናውኗል"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ወደኋላ ተመለስ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ወደኋላ ለመመለስ የመዳሰሻ ሰሌዳው ላይ የትኛውም ቦታ በሦስት ጣቶች ወደግራ ወይም ወደቀኝ ያንሸራትቱ።\n\nእንዲሁም የቁልፍ ሰሌዳ አቋራጭ + ESC ለዚህ መጠቀም ይችላሉ።"</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"በማንኛውም ጊዜ ወደ መነሻ ማያ ገፅዎ ለመሄድ ከማያ ገፅዎ ታች በሦስት ጣቶች ወደላይ ያሸብልሉ።"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"አሪፍ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ወደ መነሻ ሂድ ምልክትን አጠናቅቀዋል።"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"የተግባር ቁልፍ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"መተግበሪያዎችዎን ለመድረስ በቁልፍ ሰሌዳዎ ላይ የእርምጃ ቁልፉን ይጫኑ።"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"እንኳን ደስ አለዎት!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ሦስት ጣቶችን በመጠቀም ወደላይ ያንሸራትቱ እና ይያዙ። ምልክቶችን የበለጠ ለማወቅ መታ ያድርጉ።"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ሁሉንም መተግበሪያዎች ለማየት የቁልፍ ሰሌዳዎን ይጠቀሙ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"በማንኛውም ጊዜ የተግባር ቁልፍን ይጫኑ። ምልክቶችን የበለጠ ለማወቅ መታ ያድርጉ።"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"ተጨማሪ ደብዛዛ አሁን የብሩህነት አሞሌ ክፍል ነው"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"አሁን ከማያ ገፅዎ በላይ የብሩህነት ደረጃውን ይበልጥ በመቀነስ ማያ ገፁን ተጨማሪ ደብዛዛ ማድረግ ይችላሉ።\n\nይህ በጨለማ አካባቢ ውስጥ ሲሆኑ በተሻለ ይሠራል።"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"ተጨማሪ ደብዛዛ አቋራጭን አስወግድ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"የተጨማሪ ደብዛዛ አቋራጭን ያስወግዱ። የእርስዎን ብሩሃማነት ለመቀነስ መደበኛ የብሩሃማነት አሞሌውን ይጠቀሙ።"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ግንኙነት"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ተደራሽነት"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"መገልገያዎች"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"ግላዊነት"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"በመተግበሪያዎች የቀረበ"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ማሳያ"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ያልታወቀ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 5b844f2..1273221 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"إضافة إلى الملاحظة"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"تضمين الرابط"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"لا يمكن إضافة روابط من ملفات شخصية أخرى"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"مسجّل الشاشة"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"إضافة"</string>
<string name="manage_users" msgid="1823875311934643849">"إدارة المستخدمين"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"لا يتيح هذا الإشعار إمكانية السحب لتقسيم الشاشة."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"شبكة Wi‑Fi غير متاحة"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"وضع الأولوية"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"تم ضبط المنبه."</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"تخصيص شاشة القفل"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"الفتح لتخصيص شاشة القفل"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"لا يتوفّر اتصال Wi-Fi."</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"استخدام الكاميرا محظور."</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"استخدام الكاميرا والميكروفون محظور."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"استخدام الميكروفون محظور."</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"تعرَّف على إيماءات لوحة اللمس واختصارات لوحة المفاتيح والمزيد"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"إيماءة الرجوع"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"إيماءة الانتقال إلى الشاشة الرئيسية"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"مفتاح الإجراء"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تم"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"رجوع"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"للرجوع، مرِّر سريعًا لليمين أو لليسار باستخدام ثلاثة أصابع في أي مكان على لوحة اللمس.\n\nيمكنك أيضًا الرجوع باستخدام اختصار لوحة المفاتيح \"مفتاح الإجراء + ESC\"."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"للانتقال إلى الشاشة الرئيسية في أي وقت، مرِّر سريعًا من أسفل الشاشة إلى أعلاها بثلاثة أصابع."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"أحسنت"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"لقد أكملت التدريب على إيماءة الانتقال إلى الشاشة الرئيسية."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"مفتاح الإجراء"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"للوصول إلى التطبيقات، اضغط على مفتاح الإجراء في لوحة المفاتيح."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"تهانينا!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"مرِّر سريعًا للأعلى مع استمرار الضغط باستخدام 3 أصابع. انقر للتعرّف على المزيد من الإيماءات."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"استخدِم لوحة المفاتيح لعرض جميع التطبيقات"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"اضغط على مفتاح الإجراء في أي وقت. انقر للتعرّف على المزيد من الإيماءات."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"ميزة \"زيادة تعتيم الشاشة\" أصبحت الآن ضمن شريط مستوى السطوع"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"يمكنك الآن زيادة تعتيم الشاشة عن طريق خفض مستوى السطوع بشكل أكبر من أعلى الشاشة.\n\nيُعد هذا الخيار مناسبًا عندما تكون في مكان مظلم."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"إزالة اختصار \"زيادة تعتيم الشاشة\""</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"تمت إزالة اختصار \"زيادة تعتيم الشاشة\". لخفض مستوى سطوع شاشتك، استخدِم شريط مستوى السطوع العادي."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"إمكانية الاتصال"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"تسهيل الاستخدام"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"برامج الخدمات"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"الخصوصية"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"مقدَّمة من التطبيقات"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"العرض"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"غير معروفة"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 06f28f1..76431a0 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"যোগ দিয়ক"</string>
<string name="manage_users" msgid="1823875311934643849">"পৰিচালনা কৰক"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"এই জাননীটোৱে বিভাজিত স্ক্ৰীনলৈ টানি আনি এৰাৰ সুবিধাটো সমৰ্থন নকৰে"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ৱাই-ফাই উপলব্ধ নহয়"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"অগ্ৰাধিকাৰ ম’ড"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"এলাৰ্ম ছেট কৰা হ’ল"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"লক স্ক্ৰীন কাষ্টমাইজ কৰক"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"লক স্ক্ৰীন কাষ্টমাইজ কৰিবলৈ আনলক কৰক"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ৱাই-ফাই উপলব্ধ নহয়"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"কেমেৰা অৱৰোধ কৰা আছে"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"কেমেৰা আৰু মাইক্ৰ’ফ’ন অৱৰোধ কৰা আছে"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্ৰ’ফ’ন অৱৰোধ কৰা আছে"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"টাচ্চপেডৰ নিৰ্দেশ, কীব’ৰ্ডৰ শ্বৰ্টকাট আৰু অধিকৰ বিষয়ে জানক"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"উভতি যাওক নিৰ্দেশ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"গৃহ স্ক্ৰীনলৈ যোৱাৰ নিৰ্দেশ"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"কাৰ্য কী"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হ’ল"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"উভতি যাওক"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"উভতি যাবলৈ, টাচ্চপেডৰ যিকোনো স্থানত তিনিটা আঙুলি ব্যৱহাৰ কৰি বাওঁ বা সোঁফালে ছোৱাইপ কৰক।\n\nইয়াৰ বাবে আপুনি কীব’ৰ্ড শ্বৰ্টকাট কাৰ্য + ESC ব্যৱহাৰ কৰিবও পাৰে।"</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"যিকোনো সময়তে আপোনাৰ গৃহ স্ক্ৰীনলৈ যাবলৈ, আপোনাৰ স্ক্ৰীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ তিনিটা আঙুলিৰে ছোৱাইপ কৰক।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"সুন্দৰ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"আপুনি গৃহ স্ক্ৰীনলৈ উভতি যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"কাৰ্য কী"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"আপোনাৰ এপ্সমূহ এক্সেছ কৰিবলৈ আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক।"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"অভিনন্দন!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"তিনিটা আঙুলি ব্যৱহাৰ কৰি ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক। অধিক নিৰ্দেশ শিকিবলৈ টিপক।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"আটাইবোৰ এপ্ চাবলৈ আপোনাৰ কীব’ৰ্ড ব্যৱহাৰ কৰক"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"যিকোনো সময়তে কাৰ্য কীটোত টিপক। অধিক নিৰ্দেশ শিকিবলৈ টিপক।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"এক্সট্ৰা ডিম এতিয়া উজ্জ্বলতা বাৰৰ অংশ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"আপুনি এতিয়া আপোনাৰ স্ক্ৰীনৰ একেবাৰে ওপৰৰ পৰা উজ্জ্বলতাৰ স্তৰ আৰু অধিক হ্ৰাস কৰি স্ক্ৰীনখন এক্সট্ৰা ডিম কৰিব পাৰে।\n\nআপুনি অন্ধকাৰ পৰিৱেশত থাকিলে এই সুবিধাটোৱে আটাইতকৈ ভাল কাম কৰে।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"এক্সট্ৰা ডিম শ্বৰ্টকাট আঁতৰাওক"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"এক্সট্ৰা ডিম শ্বৰ্টকাট আঁতৰোৱা হৈছে। আপোনাৰ উজ্জ্বলতা হ্ৰাস কৰিবলৈ, নিয়মীয়া উজ্জ্বলতা বাৰ ব্যৱহাৰ কৰক।"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"সংযোগ"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"সাধ্য সুবিধা"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"সহায়ক সঁজুলি"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"গোপনীয়তা"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"এপে প্ৰদান কৰা"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ডিছপ্লে’"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"অজ্ঞাত"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 24ab6ae..7c33d3b 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Qeydə əlavə edin"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Keçid daxil edin"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g><xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Başqa profillərdən link əlavə etmək mümkün deyil"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekran yazıcısı"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran çəkilişi emal edilir"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekranın video çəkimi ərzində silinməyən bildiriş"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Əlavə edin"</string>
<string name="manage_users" msgid="1823875311934643849">"İstifadəçiləri idarə edin"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Bu bildiriş bölünmüş ekrana sürüşdürməyi dəstəkləmir"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi əlçatan deyil"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritet rejimi"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Siqnal ayarlanıb"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Kilid ekranını fərdiləşdirin"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Kilid ekranını fərdiləşdirmək üçün kiliddən çıxarın"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi əlçatan deyil"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera bloklanıb"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera və mikrofon bloklanıb"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon bloklanıb"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Taçped jestləri, klaviatura qısayolları və s. haqqında öyrənin"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geri jesti"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Əsas ekran jesti"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Əməliyyat düyməsi"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hazırdır"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri qayıdın"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Geri getmək üçün taçpeddə istənilən yerdə üç barmaqla sola və ya sağa çəkin.\n\nBunun üçün Action + ESC klaviatura qısayolundan da istifadə edə bilərsiniz."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"İstənilən vaxt ana ekrana keçmək üçün ekranın aşağısından üç barmağınızla yuxarı çəkin."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Əla!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Əsas ekrana keçid jestini tamamladınız."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Fəaliyyət açarı"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Tətbiqlərə daxil olmaq üçün klaviaturada fəaliyyət açarını basın."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Təbriklər!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Üç barmaq ilə yuxarı çəkib saxlayın. Daha çox jest öyrənmək üçün toxunun."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Bütün tətbiqlərə baxmaq üçün klaviatura istifadə edin"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"İstənilən vaxt fəaliyyət açarını basın. Daha çox jest öyrənmək üçün toxunun."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Əlavə qaraltma artıq parlaqlıq panelinin bir hissəsidir"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"İndi ekranın yuxarısında parlaqlıq səviyyəsini daha da aşağı salaraq ekranı əlavə qaralda bilərsiniz.\n\nTünd mühitdə olduqda nəticə yaxşı olur."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Əlavə qaraltma qısayolunu silin"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Əlavə qaraltma qısayolu silindi. Parlaqlığı aşağı salmaq üçün adi parlaqlıq panelindən istifadə edin."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Bağlantı"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Xüsusi imkanlar"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Kommunal xidmətlər"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Məxfilik"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Tətbiqlər tərəfindən təmin edilir"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Displey"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Naməlum"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 5efa223..bc6037a 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljaj korisnicima"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Ovo obaveštenje ne podržava prevlačenje na podeljeni ekran"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi nije dostupan"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetni režim"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je podešen"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Prilagodi zaključani ekran"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Otključajte da biste prilagodili zaključani ekran"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi nije dostupan"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučite pokrete za tačped, tasterske prečice i drugo"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za vraćanje"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za početnu stranicu"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Taster radnji"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da biste se vratili, prevucite ulevo sa tri prsta bilo gde na tačpedu.\n\nMožete da koristite i tastersku prečicu Alt + ESC za ovo."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da biste otišli na početni ekran u bilo kom trenutku, prevucite nagore od dna ekrana pomoću tri prsta."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Svaka čast!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dovršili ste pokret za povratak na početnu stranicu."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Taster radnji"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da biste pristupili aplikacijama, pritisnite taster radnji na tastaturi."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Prevucite nagore i zadržite sa tri prsta. Dodirnite da biste videli više pokreta."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Koristite tastaturu da biste pregledali sve aplikacije"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pritisnite taster radnji u bilo kom trenutku. Dodirnite da biste videli više pokreta."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Dodatno zatamnjivanje je sada deo trake za osvetljenost"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Sada možete dodatno da zatamnite ekran smanjivanjem nivoa osvetljenosti pri vrhu ekrana. \n\nOvo najbolje funkcioniše kada ste u tamnom okruženju."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Ukloni prečicu za dodatno zatamnjivanje"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Uklonjena je prečica za dodatno zatamnjivanje. Da biste smanjili osvetljenost, koristite uobičajenu traku za osvetljenost."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Povezivanje"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pristupačnost"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Uslužne aplikacije"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privatnost"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Obezbeđuju aplikacije"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Ekran"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 435d833..1f0c127 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Дадаць"</string>
<string name="manage_users" msgid="1823875311934643849">"Кіраванне карыстальнікамі"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Гэта апавяшчэнне нельга перацягнуць на падзелены экран."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Сетка Wi‑Fi недаступная"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Прыярытэтны рэжым"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будзільнік зададзены"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Наладзіць экран блакіроўкі"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Разблакіруйце, каб наладзіць экран блакіроўкі"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Сетка Wi-Fi недаступная"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера заблакіравана"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера і мікрафон заблакіраваны"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрафон заблакіраваны"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Азнаёмцеся з жэстамі для сэнсарнай панэлі, спалучэннямі клавіш і г. д."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Жэст для вяртання на папярэдні экран"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Жэст для вяртання на галоўны экран"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Клавіша дзеяння"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Гатова"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Каб вярнуцца, правядзіце трыма пальцамі ўлева ці ўправа ў любым месцы сэнсарнай панэлі.\n\nТаксама можна выкарыстоўваць спалучэнне \"клавіша дзеяння + ESC\"."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Каб у любы момант перайсці на галоўны экран, правядзіце па экране трыма пальцамі знізу ўверх."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Выдатна!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Вы навучыліся рабіць жэст для пераходу на галоўны экран."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Клавіша дзеяння"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Каб атрымаць доступ да праграм, націсніце клавішу дзеяння на клавіятуры."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Віншуем!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Правядзіце трыма пальцамі ўверх і затрымайце пальцы. Націсніце, каб азнаёміцца з іншымі жэстамі."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Выкарыстайце клавіятуру для прагляду ўсіх праграм"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Можна націснуць на клавішу дзеяння ў любы момант. Націсніце, каб азнаёміцца з іншымі жэстамі."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Цяпер кіраваць дадатковым памяншэннем яркасці можна на панэлі яркасці"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Цяпер вы можаце дадаткова зацямніць экран, яшчэ больш панізіўшы ўзровень яркасці праз налады ўверсе экрана.\n\nГэта функцыя працуе лепш за ўсё ў цёмным асяроддзі."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Выдаліць хуткую каманду для дадатковага памяншэння яркасці"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Хуткая каманда для дадатковага памяншэння яркасці выдалена. Каб паменшыць яркасць, выкарыстоўвайце звычайную панэль яркасці."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Магчымасць падключэння"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Спецыяльныя магчымасці"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Утыліты"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Прыватнасць"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Забяспечваюцца праграмамі"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Экран"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Невядома"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index adbc13a..affe260 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Добавяне към бележката"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Включване на връзката"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Не могат да се добавят връзки от други потребителски профили"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Запис на екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Добавяне"</string>
<string name="manage_users" msgid="1823875311934643849">"Потребители"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Това известие не поддържа плъзгане за разделяне на екрана"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi не е налице"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетен режим"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будилникът е зададен"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Персонализ. на заключения екран"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Отключете, за да персонализирате заключения екран"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi не е налице"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Достъпът до камерата е блокиран"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Достъпът до камерата и микрофона е блокиран"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Достъпът до микрофона е блокиран"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Научете за жестовете със сензорния панел, клавишните комбинации и др."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Жест за връщане назад"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Жест за преминаване към началния екран"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Клавиш за действия"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"За да се върнете назад, прекарайте три пръста наляво или надясно по сензорния панел.\n\nЗа целта можете също да използвате комбинацията с клавиша за действия + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"За да преминете към началния екран по всяко време, прекарайте три пръста нагоре от долната част на екрана."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Чудесно!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Изпълнихте жеста за преминаване към началния екран."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Клавиш за действия"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"За да осъществите достъп до приложенията, натиснете клавиша за действия на клавиатурата си."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Поздравления!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Плъзнете нагоре с три пръста и задръжте. Докоснете, за да научите повече жестове."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Използвайте клавиатурата, за да прегледате всички приложения"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Натиснете клавиша за действия по всяко време. Докоснете, за да научите повече жестове."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Функцията за допълнителнително затъмняване вече е част от лентата за яркостта"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Вече можете да затъмнявате екрана допълнително, като намалявате яркостта още повече от лентата в горната му част.\n\nТова е най-полезно, когато сте на тъмно място."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Премахване на прекия път за допълнително затъмняване"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Прекият път за допълнително затъмняване е премахнат. За да намалите яркостта, използвайте обикновената лента за управлението ѝ."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Свързаност"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Достъпност"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Помощни услуги"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Поверителност"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Предоставено от приложения"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Екран"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Неизвестно"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 2aa7786..497730c 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"নোটে যোগ করুন"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"লিঙ্ক যোগ করুন"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"অন্যান্য প্রোফাইল থেকে লিঙ্ক যোগ করা যাবে না"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"স্ক্রিন রেকর্ডার"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"যোগ করুন"</string>
<string name="manage_users" msgid="1823875311934643849">"ব্যবহারকারীদের ম্যানেজ করুন"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"\'স্প্লিটস্ক্রিন\' মোডে এই বিজ্ঞপ্তি টেনে আনা যাবে না"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ওয়াই-ফাই উপলভ্য নেই"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"প্রায়োরিটি মোড"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"অ্যালার্ম সেট করা হয়েছে"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"লক স্ক্রিন কাস্টমাইজ করুন"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"লক স্ক্রিন কাস্টমাইজ করতে আনলক করুন"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ওয়াই-ফাই উপলভ্য নয়"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ক্যামেরার অ্যাক্সেস ব্লক করা আছে"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ক্যামেরা এবং মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"মাইক্রোফোনের অ্যাক্সেস ব্লক করা আছে"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"টাচপ্যাড জেসচার, কীবোর্ড শর্টকাট এবং আরও অনেক কিছু সম্পর্কে জানুন"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ফিরে যাওয়ার জেসচার"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"হোমপেজে যাওয়ার জেসচার"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"অ্যাকশন কী"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"হয়ে গেছে"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ফিরে যান"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ফিরে যেতে, টাচপ্যাডে যেকোনও জায়গায় তিনটি আঙুল দিয়ে বাঁদিক বা ডানদিকে সোয়াইপ করুন।\n\nএছাড়া, এটির জন্য আপনি কীবোর্ড শর্টকাট অ্যাকশন + ESC বোতাম প্রেস করতে পারবেন।"</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"যেকোনও সময়ে আপনার হোম স্ক্রিনে যেতে, আপনার স্ক্রিনের একদম নিচের থেকে তিনটি আঙুল দিয়ে উপরের দিকে সোয়াইপ করুন।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"সাবাস!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"জেসচার ব্যবহার করে কীভাবে হোমে ফিরে যাওয়া যায় সেই সম্পর্কে আপনি জেনেছেন।"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"অ্যাকশন কী"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"আপনার অ্যাপ অ্যাক্সেস করতে, কীবোর্ডে অ্যাকশন কী প্রেস করুন"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"অভিনন্দন!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"তিনটি আঙুল ব্যবহার করে উপরের দিকে সোয়াইপ করে ধরে রাখুন। আরও জেসচার সম্পর্কে জানতে ট্যাপ করুন।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"সব অ্যাপ দেখতে আপনার কীবোর্ড ব্যবহার করুন"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"যেকোনও সময় অ্যাকশন কী প্রেস করুন। আরও জেসচার সম্পর্কে জানতে ট্যাপ করুন।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"\'অতিরিক্ত কম ব্রাইটনেস\' ফিচার এখন ব্রাইটনেস বারের একটি অংশ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"আপনি এখন স্ক্রিনের উপর থেকে ব্রাইটনেস লেভেল কমিয়েও, স্ক্রিন অতিরিক্ত কম ব্রাইট করতে পারবেন।\n\nআপনি অন্ধকার পরিবেশে থাকলে এটি সবথেকে ভালো কাজ করে।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"\'অতিরিক্ত কম ব্রাইটনেস\' ফিচারের শর্টকাট সরান"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"\'অতিরিক্ত কম ব্রাইটনেস\' ফিচারের শর্টকাট সরানো হয়েছে। আপনার ব্রাইটনেস কম করতে, সাধারণ ব্রাইটনেস বার ব্যবহার করুন।"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"কানেক্টিভিটি"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"অ্যাক্সেসিবিলিটি"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"উপযোগিতা"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"গোপনীয়তা"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"অ্যাপের তরফ থেকে দেওয়া"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ডিসপ্লে"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"অজানা"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 4802af8..509bf6f 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj u bilješku"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Uključi link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Nije moguće dodati linkove s drugih profila"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljajte korisnicima"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Ovo obavještenje ne podržava prevlačenje na podijeljeni ekran"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi je nedostupan"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Način rada Prioriteti"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Prilagodi zaključani ekran"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Otključajte da prilagodite zaključani ekran"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi mreža nije dostupna"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon su blokirani"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Saznajte više o pokretima na dodirnoj podlozi, prečicama tastature i drugim opcijama"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za povratak"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za povratak na početni ekran"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tipka radnji"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazad"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da se vratite, prevucite ulijevo ili udesno s tri prsta bilo gdje na dodirnoj podlozi.\n\nZa ovo možete koristiti i radnju za prečicu i Esc na tastaturi."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da odete na početni ekran bilo kada, prevucite s dna ekrana nagore s tri prsta."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Lijepo!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Savladali ste pokret za odlazak na početni ekran."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka radnji"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da pristupite aplikacijama, pritisnite tipku radnji na tastaturi."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Prevucite nagore i zadržite s tri prsta. Dodirnite da saznate za više pokreta."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Koristite tastaturu da pregledate sve aplikacije"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pritisnite tipku radnji bilo kada. Dodirnite da saznate za više pokreta."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Dodatno zatamnjenje je sada dio trake za osvijetljenost"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Sada možete dodatno zatamniti ekran daljnjim smanjenjem nivoa osvijetljenosti s vrha ekrana.\n\nOvo najbolje funkcionira u tamnom okruženju."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Ukloni prečicu za dodatno zatamnjenje"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Prečica za dodatno zatamnjenje je uklonjena. Da smanjite osvijetljenost, koristite običnu traku za osvijetljenost."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Povezivost"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pristupačnost"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Uslužni programi"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privatnost"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Pružaju aplikacije"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Prikaz"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 10fedd8..8c9c597 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Afegeix a una nota"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Inclou l\'enllaç"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"No es poden afegir enllaços des d\'altres perfils"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Gravació de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Afegeix"</string>
<string name="manage_users" msgid="1823875311934643849">"Gestiona usuaris"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Aquesta notificació no es pot arrossegar a la pantalla dividida"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi no disponible"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritat"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalitza pantalla de bloqueig"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloqueja per personalitzar la pantalla de bloqueig"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"No hi ha cap Wi‑Fi disponible"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La càmera està bloquejada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La càmera i el micròfon estan bloquejats"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micròfon està bloquejat"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprèn els gestos del ratolí tàctil, les tecles de drecera i més"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gest Enrere"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gest Inici"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tecla d\'acció"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fet"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Torna"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Per tornar enrere, llisca cap a l\'esquerra o cap a la dreta amb tres dits en qualsevol lloc del ratolí tàctil.\n\nTambé pots utilitzar les tecles d\'accions de drecera+Esc."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Per anar a la pantalla d\'inici en qualsevol moment, fes lliscar tres dits cap amunt des de la part inferior de la pantalla."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Molt bé!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Has completat el gest per anar a la pantalla d\'inici."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla d\'acció"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Per accedir a les aplicacions, prem la tecla d\'acció al teclat."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Enhorabona!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Llisca cap amunt amb tres dits i mantén premut. Toca per aprendre més gestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Utilitza el teclat per veure totes les aplicacions"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Prem la tecla d\'acció en qualsevol moment. Toca per aprendre més gestos."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Atenuació extra ara forma part de la barra de brillantor"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Ara pots atenuar encara més la pantalla abaixant-ne el nivell de brillantor des de la part superior.\n\nFunciona millor si et trobes en un lloc fosc."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Suprimeix la drecera d\'atenuació extra"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"S\'ha suprimit la drecera d\'atenuació extra. Per abaixar la brillantor, utilitza la barra de brillantor normal."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivitat"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibilitat"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitats"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privadesa"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Proporcionat per aplicacions"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Pantalla"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconegut"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index f995b29..6d2328e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Přidat"</string>
<string name="manage_users" msgid="1823875311934643849">"Spravovat uživatele"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Toto oznámení nepodporuje přetažení na rozdělenou obrazovku"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Síť Wi‑Fi není k dispozici"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritní režim"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Je nastaven budík"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Přizpůsobit obrazovku uzamčení"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Obrazovku uzamčení upravíte, když zařízení odemknete"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Síť Wi-Fi není dostupná"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokována"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofon jsou blokovány"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokován"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučte se gesta touchpadu, klávesové zkratky a další"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto zpět"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto domů"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Akční klávesa"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zpět"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pokud se chcete vrátit zpět, stačí kdekoli na touchpadu přejet třemi prsty doleva nebo doprava.\n\nMůžete také použít klávesovou zkratku Akce + ESC."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Na plochu přejdete kdykoli přejetím třemi prsty ze spodní části obrazovky nahoru."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Skvělé!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dokončili jste gesto pro přechod na plochu."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Akční klávesa"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Přístup k aplikacím získáte stisknutím akční klávesy na klávesnici."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulujeme!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Přejeďte třemi prsty nahoru a podržte je. Další gesta zjistíte klepnutím."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Zobrazení všech aplikací pomocí klávesnice"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Kdykoli stiskněte akční klávesu. Další gesta zjistíte klepnutím."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Na sloupci jasu lze nově nastavit velmi tmavou obrazovku"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Obrazovku můžete v horní části nastavit jako velmi tmavou tím, že ještě víc snížíte jas.\n\nNejlépe to funguje ve tmavém prostředí."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Odstranit zkratku pro velmi tmavou obrazovku"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Zkratka pro velmi tmavou obrazovku byla odstraněna. Jas můžete snížit pomocí standardního sloupce jasu."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Připojení"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Přístupnost"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Nástroje"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Ochrana soukromí"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Poskytováno aplikacemi"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Displej"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznámé"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 3b74a6d..261cf33 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Føj til note"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Inkluder link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Der kan ikke tilføjes links fra andre profiler"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skærmoptagelse"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skærmoptagelse"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Konstant notifikation om skærmoptagelse"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Tilføj"</string>
<string name="manage_users" msgid="1823875311934643849">"Administrer brugere"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Denne notifikation kan ikke trækkes til en opdelt skærm"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Ingen tilgængelig Wi-Fi-forbindelse"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tilstanden Prioritet"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er indstillet"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Tilpas låseskærm"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Lås op for at tilpasse låseskærmen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ikke tilgængeligt"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokeret"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Der er blokeret for kameraet og mikrofonen"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokeret"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Se bevægelser på touchpladen, tastaturgenveje m.m."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Bevægelse for at gå tilbage"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Bevægelse for at gå til startskærm"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Handlingstast"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Udfør"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbage"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Du kan gå tilbage ved at stryge mod venstre eller højre med tre fingre et vilkårligt sted på touchpladen.\n\nDu kan også bruge tastaturgenvejen Alt + Esc."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Du kan til enhver tid stryge opad med tre fingre fra bunden af skærmen, hvis du vil gå til startskærmen."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Sådan!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du har fuldført bevægelsen for Gå til startskærmen."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Handlingstast"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Du kan tilgå alle dine apps ved at trykke på handlingstasten på dit tastatur."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tillykke!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Stryg opad, og hold tre fingre nede. Tryk for at lære flere bevægelser."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Brug dit tastatur til at se alle apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tryk på handlingstasten når som helst. Tryk for at lære flere bevægelser."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Ekstra dæmpet belysning er nu en del af lysstyrkebjælken"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Du kan nu dæmpe skærmens belysning ekstra meget ved at reducere lysstyrken endnu mere fra toppen af skærmen.\n\nDette fungerer bedst i mørke omgivelser."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Fjern genvejen til ekstra dæmpet belysning"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Genvejen til ekstra dæmpet belysning er fjernet. Brug den almindelige lysstyrkebjælke til at reducere lysstyrken."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Forbindelse"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Hjælpefunktioner"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Værktøjer"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privatliv"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Fra apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Skærm"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ukendt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index fa7ad56..f0e1871 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Zu Notiz hinzufügen"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Link einschließen"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Es dürfen keine Links aus anderen Profilen hinzugefügt werden"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Bildschirmaufzeichnung"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Hinzufügen"</string>
<string name="manage_users" msgid="1823875311934643849">"Nutzer verwalten"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Diese Benachrichtigung lässt sich nicht auf einen Splitscreen ziehen"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WLAN nicht verfügbar"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritätsmodus"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wecker gestellt"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Sperrbildschirm personalisieren"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Zum Anpassen des Sperrbildschirms entsperren"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Kein WLAN verfügbar"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera blockiert"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera und Mikrofon blockiert"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon blockiert"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Informationen zu Touchpad-Gesten, Tastenkombinationen und mehr"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Touch-Geste „Zurück“"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Touch-Geste „Startbildschirm“"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Aktionstaste"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fertig"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Zurück"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Wenn du zurückgehen möchtest, wische an einer beliebigen Stelle des Touchpads mit drei Fingern nach links oder rechts.\n\nDu kannst stattdessen auch die Tastenkombination „Aktion“ + „ESC“ verwenden."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Du kannst jederzeit zum Startbildschirm gehen, indem du mit drei Fingern vom unteren Displayrand nach oben wischst."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Sehr gut!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du hast den Schritt für die „Startbildschirm“-Geste abgeschlossen."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Aktionstaste"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Wenn du auf deine Apps zugreifen möchtest, drücke auf der Tastatur die Aktionstaste."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Glückwunsch!"</string>
@@ -1434,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Wische mit 3 Fingern nach oben und halte das Touchpad gedrückt. Tippe für mehr Infos zu Touch-Gesten."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Über die Tastatur alle Apps aufrufen"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Du kannst jederzeit die Aktionstaste drücken. Tippe für mehr Infos zu Touch-Gesten."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"„Extradunkel“ jetzt auf Helligkeitsleiste verfügbar"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Du kannst das Display jetzt extradunkel machen, indem du die Helligkeit vom oberen Displayrand aus noch weiter senkst.\n\nDas funktioniert in dunklen Umgebungen am besten."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Verknüpfung für „Extradunkel“ entfernen"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Verknüpfung für „Extradunkel“ wurde entfernt. Wenn du die Helligkeit reduzieren möchtest, verwende einfach die normale Helligkeitsleiste."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 26f1c56..16082cb 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Προσθήκη σε σημείωση"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Συμπερίληψη συνδέσμου"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Δεν είναι δυνατή η προσθήκη συνδέσμων από άλλα προφίλ"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Εγγραφή οθόνης"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Επεξεργασία εγγραφής οθόνης"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ειδοποίηση σε εξέλιξη για μια περίοδο λειτουργίας εγγραφής οθόνης"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Προσθήκη"</string>
<string name="manage_users" msgid="1823875311934643849">"Διαχ. χρηστών"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Αυτή η ειδοποίηση δεν υποστηρίζει τη μεταφορά με σύρσιμο για τον διαχωρισμό οθόνης"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Το Wi‑Fi δεν είναι διαθέσιμο"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Λειτουργία προτεραιότητας"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Το ξυπνητήρι ρυθμίστηκε"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Προσαρμογή οθόνης κλειδώματος"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ξεκλειδώστε για προσαρμογή της οθόνης κλειδώματος"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Δεν υπάρχει διαθέσιμο δίκτυο Wi-Fi"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Η κάμερα έχει αποκλειστεί"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Η κάμερα και το μικρόφωνο έχουν αποκλειστεί"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Το μικρόφωνο έχει αποκλειστεί"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Μάθετε κινήσεις επιφάνειας αφής, συντομεύσεις πληκτρολογίου και άλλα"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Κίνηση επιστροφής"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Κίνηση μετάβασης στην αρχική οθόνη"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Πλήκτρο ενέργειας"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Τέλος"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Επιστροφή"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Για να επιστρέψετε, σύρετε προς τα αριστερά ή προς τα δεξιά χρησιμοποιώντας τρία δάχτυλα σε οποιοδήποτε σημείο της επιφάνειας αφής.\n\nΜπορείτε επίσης να χρησιμοποιήσετε τη συντόμευση πληκτρολογίου Action + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Για μετάβαση στην αρχική οθόνη ανά πάσα στιγμή, σύρετε προς τα επάνω με τρία δάχτυλα από το κάτω μέρος της οθόνης."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Ωραία!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ολοκληρώσατε την κίνηση μετάβασης στην αρχική οθόνη."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Πλήκτρο ενέργειας"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Για να αποκτήσετε πρόσβαση στις εφαρμογές σας, πατήστε το πλήκτρο ενέργειας στο πληκτρολόγιό σας."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Συγχαρητήρια!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Σύρετε προς τα πάνω με τρία δάχτυλα και μην τα σηκώσετε. Πατήστε για να δείτε περισσότερες κινήσεις."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Χρήση του πληκτρολογίου για προβολή όλων των εφαρμογών"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Πιέστε το πλήκτρο ενέργειας ανά πάσα στιγμή. Πατήστε για να μάθετε περισσότερες κινήσεις."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Η επιπλέον μείωση φωτεινότητας είναι τώρα μέρος της γραμμής φωτεινότητας"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Τώρα μπορείτε να μειώσετε επιπλέον τη φωτεινότητα της οθόνης, χαμηλώνοντας το επίπεδο φωτεινότητας ακόμα περισσότερο από το επάνω μέρος της οθόνης.\n\nΑυτό λειτουργεί καλύτερα όταν βρίσκεστε σε σκοτεινό περιβάλλον."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Κατάργηση συντόμευσης επιπλέον μείωσης φωτεινότητας"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Η συντόμευση της επιπλέον μείωσης φωτεινότητας καταργήθηκε. Για να χαμηλώσετε τη φωτεινότητα, χρησιμοποιήστε την κανονική γραμμή φωτεινότητας."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Συνδεσιμότητα"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Προσβασιμότητα"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Βοηθητικά προγράμματα"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Απόρρητο"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Παρέχεται από εφαρμογές"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Προβολή"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Άγνωστο"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 24922ac..e0bf0d6 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Add to note"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Include link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Links can\'t be added from other profiles"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Screen recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"This notification does not support dragging to split screen"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Customise lock screen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Unlock to customise lock screen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe up and hold using three fingers. Tap to learn more gestures."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use your keyboard to view all apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Press the action key at any time. Tap to learn more gestures."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Extra dim is now part of the brightness bar"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"You can now make the screen extra dim by lowering the brightness level even further from the top of your screen.\n\nThis works best when you\'re in a dark environment."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Remove extra dim shortcut"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Extra dim shortcut removed. To lower your brightness, use the regular brightness bar."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivity"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilities"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacy"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Provided by apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Display"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 88f1753..6f626e9 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1289,6 +1289,7 @@
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"This notification does not support dragging to split screen"</string>
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Location active"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
@@ -1345,6 +1346,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Customize lock screen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Unlock to customize lock screen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string>
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Location active"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera blocked"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone blocked"</string>
@@ -1400,7 +1402,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts, and more"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + ESC for this."</string>
@@ -1410,6 +1412,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Great job!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
@@ -1433,10 +1439,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe up and hold using three fingers. Tap to learn more gestures."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use your keyboard to view all apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Press the action key at any time. Tap to learn more gestures."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Extra dim is now part of the brightness bar"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"You can now make the screen extra dim by lowering the brightness level even further from the top of your screen.\n\nThis works best when you\'re in a dark environment."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Remove extra dim shortcut"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Extra dim shortcut removed. To lower your brightness, use the regular brightness bar."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Extra dim is now part of the brightness slider"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"You can now make the screen extra dim by lowering the brightness level even further.\n\nSince this feature is now part of the brightness slider, extra dim shortcuts are being removed."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Remove extra dim shortcuts"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Extra dim shortcuts removed"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivity"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilities"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 24922ac..e0bf0d6 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Add to note"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Include link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Links can\'t be added from other profiles"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Screen recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"This notification does not support dragging to split screen"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Customise lock screen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Unlock to customise lock screen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe up and hold using three fingers. Tap to learn more gestures."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use your keyboard to view all apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Press the action key at any time. Tap to learn more gestures."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Extra dim is now part of the brightness bar"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"You can now make the screen extra dim by lowering the brightness level even further from the top of your screen.\n\nThis works best when you\'re in a dark environment."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Remove extra dim shortcut"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Extra dim shortcut removed. To lower your brightness, use the regular brightness bar."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivity"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilities"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacy"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Provided by apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Display"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 24922ac..e0bf0d6 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Add to note"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Include link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Links can\'t be added from other profiles"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Screen recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"This notification does not support dragging to split screen"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Customise lock screen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Unlock to customise lock screen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera is blocked"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone is blocked"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts and more"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + Esc for this."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe up and hold using three fingers. Tap to learn more gestures."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use your keyboard to view all apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Press the action key at any time. Tap to learn more gestures."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Extra dim is now part of the brightness bar"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"You can now make the screen extra dim by lowering the brightness level even further from the top of your screen.\n\nThis works best when you\'re in a dark environment."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Remove extra dim shortcut"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Extra dim shortcut removed. To lower your brightness, use the regular brightness bar."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivity"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilities"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacy"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Provided by apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Display"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index e8b3206..936b64d 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1289,6 +1289,7 @@
<string name="add" msgid="81036585205287996">"Add"</string>
<string name="manage_users" msgid="1823875311934643849">"Manage users"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"This notification does not support dragging to split screen"</string>
+ <string name="dream_overlay_location_active" msgid="6484763493158166618">"Location active"</string>
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi unavailable"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm set"</string>
@@ -1345,6 +1346,7 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Customize lock screen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Unlock to customize lock screen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi not available"</string>
+ <string name="location_active_dream_overlay_content_description" msgid="6208885541020673916">"Location active"</string>
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera blocked"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera and microphone blocked"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone blocked"</string>
@@ -1400,7 +1402,7 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Learn touchpad gestures, keyboards shortcuts, and more"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Back gesture"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Home gesture"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
+ <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"View recent apps"</string>
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Done"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Go back"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"To go back, swipe left or right using three fingers anywhere on the touchpad.\n\nYou can also use the keyboard shortcut Action + ESC for this."</string>
@@ -1410,6 +1412,10 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"To go to your home screen at any time, swipe up with three fingers from the bottom of your screen."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Nice!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"You completed the go home gesture."</string>
+ <string name="touchpad_recent_apps_gesture_action_title" msgid="934906836867137906">"View recent apps"</string>
+ <string name="touchpad_recent_apps_gesture_guidance" msgid="6012057247259983871">"Swipe up and hold using three fingers on your touchpad."</string>
+ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"Great job!"</string>
+ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string>
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"To access your apps, press the action key on your keyboard."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Congratulations!"</string>
@@ -1433,10 +1439,10 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe up and hold using three fingers. Tap to learn more gestures."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use your keyboard to view all apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Press the action key at any time. Tap to learn more gestures."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Extra dim is now part of the brightness bar"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"You can now make the screen extra dim by lowering the brightness level even further from the top of your screen.\n\nThis works best when you\'re in a dark environment."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Remove extra dim shortcut"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Extra dim shortcut removed. To lower your brightness, use the regular brightness bar."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="910988771011857460">"Extra dim is now part of the brightness slider"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="4453123359258743230">"You can now make the screen extra dim by lowering the brightness level even further.\n\nSince this feature is now part of the brightness slider, extra dim shortcuts are being removed."</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="3947537827396916005">"Remove extra dim shortcuts"</string>
+ <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="165474092660941104">"Extra dim shortcuts removed"</string>
<string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectivity"</string>
<string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string>
<string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilities"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 42c3510..96af732 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Agregar a la nota"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Incluir vínculo"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"No se pueden agregar vínculos desde otros perfiles"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Grabadora de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación constante para una sesión de grabación de pantalla"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Agregar"</string>
<string name="manage_users" msgid="1823875311934643849">"Administrar usuarios"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificación no admite arrastrar entre pantallas divididas"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"La red Wi-Fi no está disponible"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo prioridad"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Se estableció la alarma"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar pantalla de bloqueo"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloquea para personalizar la pantalla de bloqueo"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi no disponible"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"La cámara está bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"La cámara y el micrófono están bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"El micrófono está bloqueado"</string>
@@ -1393,21 +1396,16 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícono de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícono de expandir"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
- <!-- no translation found for launch_keyboard_tutorial_notification_title (8849933155160522519) -->
- <skip />
- <!-- no translation found for launch_keyboard_tutorial_notification_content (2880339951512757918) -->
- <skip />
- <!-- no translation found for launch_touchpad_tutorial_notification_title (2243780062772196901) -->
- <skip />
- <!-- no translation found for launch_touchpad_tutorial_notification_content (7931085031240753226) -->
- <skip />
- <!-- no translation found for launch_keyboard_touchpad_tutorial_notification_title (1940023776496198762) -->
- <skip />
- <!-- no translation found for launch_keyboard_touchpad_tutorial_notification_content (1780725168171929365) -->
- <skip />
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navega con el teclado"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string>
+ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navega con el panel táctil"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprende los gestos del panel táctil"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navega con el teclado y el panel táctil"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprende sobre los gestos del panel táctil, las combinaciones de teclas y mucho más"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto atrás"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto para ir a la pantalla principal"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tecla de acción"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Listo"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para volver, desliza tres dedos hacia la derecha o la izquierda en cualquier lugar del panel táctil.\n\nPara completar esta acción, también puedes usar la combinación de teclas Action + ESC."</string>
@@ -1417,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para ir a la pantalla principal en cualquier momento, desliza hacia arriba desde la parte inferior de la pantalla con tres dedos."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"¡Muy bien!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Completaste el gesto para ir al inicio."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de acción"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acceder a las apps, presiona la tecla de acción en el teclado."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"¡Felicitaciones!"</string>
@@ -1440,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Desliza hacia arriba con tres dedos y mantenlos presionados. Presiona para aprender más gestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa el teclado para ver todas las apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Presiona la tecla de acción en cualquier momento. Presiona para aprender más gestos."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"La atenuación extra ahora es parte de la barra de brillo"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Ahora puedes bajar el nivel del brillo desde la parte superior de la pantalla para atenuarla aún más.\n\nEsto funciona mejor si estás en un ambiente oscuro."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Quitar la combinación de teclas de atenuación extra"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Se quitó el atajo de atenuación extra. Para bajar el brillo, usa la barra de brillo normal."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 6595258..fb8ceec 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Añadir"</string>
<string name="manage_users" msgid="1823875311934643849">"Gestionar usuarios"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificación no se puede arrastrar a la pantalla dividida"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi no disponible"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo prioritario"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma añadida"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar pantalla de bloqueo"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloquea para personalizar la pantalla de bloqueo"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Red Wi-Fi no disponible"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Cámara bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Cámara y micrófono bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrófono bloqueado"</string>
@@ -1392,21 +1396,16 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icono de desplegar"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
- <!-- no translation found for launch_keyboard_tutorial_notification_title (8849933155160522519) -->
- <skip />
- <!-- no translation found for launch_keyboard_tutorial_notification_content (2880339951512757918) -->
- <skip />
- <!-- no translation found for launch_touchpad_tutorial_notification_title (2243780062772196901) -->
- <skip />
- <!-- no translation found for launch_touchpad_tutorial_notification_content (7931085031240753226) -->
- <skip />
- <!-- no translation found for launch_keyboard_touchpad_tutorial_notification_title (1940023776496198762) -->
- <skip />
- <!-- no translation found for launch_keyboard_touchpad_tutorial_notification_content (1780725168171929365) -->
- <skip />
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Desplázate con el teclado"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Aprende combinaciones de teclas"</string>
+ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Desplázate con el panel táctil"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Aprende gestos del panel táctil"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Desplázate con el teclado y el panel táctil"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprende gestos del panel táctil, combinaciones de teclas y más"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto para volver"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto para ir al inicio"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tecla de acción"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hecho"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atrás"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para volver, desliza con tres dedos hacia la izquierda o la derecha en cualquier parte del panel táctil.\n\nTambién puedes hacerlo con la combinación de teclas asignada + Esc."</string>
@@ -1416,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para ir a la pantalla de inicio en cualquier momento, desliza hacia arriba con tres dedos desde la parte inferior de la pantalla."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"¡Muy bien!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Has completado el gesto para ir a la pantalla de inicio."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de acción"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acceder a tus aplicaciones, pulsa la tecla de acción de tu teclado."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"¡Enhorabuena!"</string>
@@ -1439,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Desliza hacia arriba y mantén pulsado con tres dedos. Toca para aprender a usar más gestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa el teclado para ver todas las aplicaciones"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pulsa la tecla de acción en cualquier momento. Toca para aprender a usar más gestos."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"La atenuación extra ahora forma parte de la barra de brillo"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Ahora puedes atenuar aún más tu pantalla reduciendo el nivel de brillo desde la parte superior.\n\nFunciona mejor cuando estás en un lugar con poca luz."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Eliminar acceso directo a la atenuación extra"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Acceso directo a la atenuación extra eliminado. Para reducir el brillo, usa la barra de brillo normal."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 7042ac13..430fcf0 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Lisa märkmesse"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Kaasa link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Teistelt profiilidelt ei saa linke lisada"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekraanisalvesti"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Lisa"</string>
<string name="manage_users" msgid="1823875311934643849">"Kasutajate haldamine"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"See märguanne ei toeta jagatud ekraanikuvale lohistamist."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi pole saadaval"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režiim Prioriteetne"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm on määratud"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Kohanda lukustuskuva"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Lukustuskuva kohandamiseks avage"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi pole saadaval"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kaamera on blokeeritud"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kaamera ja mikrofon on blokeeritud"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon on blokeeritud"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Õppige puuteplaadi liigutusi, klaviatuuri otseteid ja palju muud"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tagasiliikumisliigutus"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Avakuvale liikumise liigutus"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Toiminguklahv"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tagasi"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Tagasiliikumiseks pühkige puuteplaadil kolme sõrmega vasakule või paremale.\n\nSamuti saate selle jaoks kasutada klaviatuuri otseteed toiminguklahv + paoklahv."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Mis tahes ajal avakuvale liikumiseks pühkige kolme sõrmega ekraanikuva allosast üles."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Hästi tehtud!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Tegite avakuvale minemise liigutuse."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Toiminguklahv"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Rakendustele juurdepääsemiseks vajutage klaviatuuril toiminguklahvi."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Õnnitleme!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Pühkige kolme sõrmega üles ja hoidke sõrmi plaadil. Puudutage žestide kohta lisateabe saamiseks."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Klaviatuuri kasutamine kõigi rakenduste kuvamiseks"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Vajutage soovitud ajal toiminguklahvi. Puudutage žestide kohta lisateabe saamiseks."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Funktsioon „Eriti tume“ on nüüd osa ereduse reguleerimise ribast"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Nüüd saate muuta ekraani eriti tumedaks, vähendades ereduse taset ekraani ülaosast veelgi rohkem.\n\nSee toimib kõige paremini hämaras keskkonnas."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Eemalda funktsiooni „Eriti tume“ otsetee"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Funktsiooni „Eriti tume“ otsetee eemaldati. Kasutage ereduse vähendamiseks tavapärast ereduse reguleerimise riba."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Ühenduvus"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Juurdepääsetavus"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utiliidid"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privaatsus"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Rakendustelt"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Kuva"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Teadmata"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index e51e3753..ef6990c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Gehitu oharrean"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Sartu esteka"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Ezin da beste profiletako estekarik gehitu"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Pantaila-grabagailua"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Gehitu"</string>
<string name="manage_users" msgid="1823875311934643849">"Kudeatu erabiltzaileak"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Jakinarazpen hau ezin da arrastatu pantaila zatitura"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi-konexioa ez dago erabilgarri"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Lehentasun modua"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma ezarrita dago"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Pertsonalizatu pantaila blokeatua"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desblokeatu eta pertsonalizatu pantaila blokeatua"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi-konexioa ez dago erabilgarri"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera blokeatuta dago"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera eta mikrofonoa blokeatuta daude"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonoa blokeatuta dago"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Ikasi ukipen-paneleko keinuak, lasterbideak eta abar"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Atzera egiteko keinua"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Orri nagusira joateko keinua"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Ekintza-tekla"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Eginda"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Egin atzera"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Atzera egiteko, pasatu 3 hatz ezkerrera edo eskuinera ukipen-panelean.\n\nEkintza + Ihes lasterbidea ere erabil dezakezu horretarako."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Orri nagusira joateko, pasatu 3 hatz pantailaren behealdetik gora."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Ederki!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ikasi duzu hasierako pantailara joateko keinua."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Ekintza-tekla"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Aplikazioak atzitzeko, sakatu teklatuko ekintza-tekla."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Zorionak!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Pasatu 3 hatz gora eta eduki sakatuta. Sakatu keinu gehiago ikasteko."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Erabili teklatua aplikazio guztiak ikusteko"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Sakatu ekintza-tekla edonoiz. Sakatu keinu gehiago ikasteko."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Orain, argitasun-barran agertzen da Are ilunago"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Orain, pantaila are ilunago jar dezakezu, pantailaren goialdetik argitasun-maila are gehiago jaitsita.\n\nIngurune ilun batean zaudenean funtzionatzen du ondoen."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Kendu Are ilunago eginbidearen lasterbidea"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Kendu da Are ilunago eginbidearen lasterbidea. Argitasuna murrizteko, erabili argitasun-barra arrunta."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Konexioa"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Erabilerraztasuna"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Zerbitzu-aplikazioak"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Pribatutasuna"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Aplikazioenak"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Pantaila"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ezezagunak"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 13d403b..7239b9b7 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"افزودن"</string>
<string name="manage_users" msgid="1823875311934643849">"مدیریت کاربران"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"این اعلان از عملکرد کشیدن به صفحهٔ دونیمه پشتیبانی نمیکند"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi دردسترس نیست"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"حالت اولویت"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"زنگ ساعت تنظیم شد"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"سفارشیسازی صفحه قفل"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"برای سفارشیسازی صفحه قفل، قفل را باز کنید"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi دردسترس نیست"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"دوربین مسدود شده است"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"دوربین و میکروفون مسدود شدهاند"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"میکروفون مسدود شده است"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"آشنایی با اشارههای صفحه لمسی، میانبرهای صفحهکلید، و موارد دیگر"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"اشاره برگشت"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"اشاره صفحه اصلی"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"دکمه کنش"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تمام"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"برگشتن"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"برای برگشتن، در هر جایی از صفحه لمسی، با سه انگشت تند بهچپ یا راست بکشید.\n\nبرای این کار میتوانید از میانبر صفحهکلید «کنش + گریز» هم استفاده کنید."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"برای رفتن به صفحه اصلی در هرزمانی، با سه انگشت از پایین صفحهنمایش تند بهبالا بکشید."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"آفرین!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"اشاره رفتن به صفحه اصلی را تکمیل کردید."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"دکمه کنش"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"برای دسترسی به برنامههایتان، دکمه کنش در صفحهکلید را فشار دهید."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"تبریک!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"با سه انگشت تند بهبالا بکشید و نگه دارید. برای آشنایی با اشارههای بیشتر، تکضرب بزنید."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"برای مشاهده همه برنامهها، از صفحهکلید استفاده کنید"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"در هرزمانی دکمه کنش را فشار دهید. برای آشنایی با اشارههای بیشتر، تکضرب بزنید."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"«بسیار کمنور» اکنون بخشی از نوار روشنایی است"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ازاینپس میتوانید با پایینتر آوردن سطح روشنایی از بالای صفحهنمایش، صفحهنمایش را بسیار کمنور کنید.\n\nاین ویژگی زمانی بهترین عملکرد را دارد که در محیطی تاریک باشید."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"حذف میانبر «بسیار کمنور»"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"میانبر «بسیار کمنور» حذف شد. برای کم کردن روشنایی، از نوار معمول روشنایی استفاده کنید."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"اتصالپذیری"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"دسترسپذیری"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"برنامههای کمکی"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"حریم خصوصی"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ارائهشده از برنامهها"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"نمایشگر"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"نامشخص"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index ab31329..d0133c7 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Lisää muistiinpanoon"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Lisää linkki"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Linkkejä ei voi lisätä muista profiileista"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Näytön tallentaja"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Lisää"</string>
<string name="manage_users" msgid="1823875311934643849">"Ylläpidä käyttäjiä"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Ilmoitus ei tue jaetulle näytölle vetämistä"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ei ole saatavilla"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tärkeät-tila"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Hälytys asetettu"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Muokkaa lukitusnäyttöä"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Voit muokata lukitusnäyttöä, kun avaat lukituksen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi-yhteys ei ole käytettävissä"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera estetty"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ja mikrofoni estetty"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoni estetty"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Opettele kosketuslevyn eleitä, pikanäppäimiä ja muuta"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Takaisin-ele"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Etusivu-ele"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Toimintonäppäin"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Valmis"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Takaisin"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Jos haluat siirtyä takaisin, pyyhkäise kosketuslevyllä vasemmalle tai oikealle kolmella sormella.\n\nVoit myös käyttää pikanäppäinyhdistelmää toimintonäppäin + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Voit siirtyä aloitusnäytölle milloin tahansa pyyhkäisemällä ylös näytön alareunasta kolmella sormella."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Hienoa!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Olet oppinut aloitusnäytölle palaamiseleen."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Toimintonäppäin"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Voit käyttää sovelluksia painamalla näppäimistön toimintonäppäintä."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Onnittelut!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Pyyhkäise ylös ja pidä kosketuslevyä painettuna kolmella sormella. Lue lisää eleistä napauttamalla."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Kaikkien sovellusten näkeminen näppäimistön avulla"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Voit painaa toimintonäppäintä milloin tahansa. Lue lisää eleistä napauttamalla."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Erittäin himmeä on nyt osa kirkkauspalkkia"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Voit nyt tehdä näytöstä erittäin himmeän vähentämällä kirkkautta vieläkin enemmän näytön yläreunasta.\n\nTämä toimii parhaiten pimeässä ympäristössä."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Poista erittäin himmeä ‑pikakomento"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Erittäin himmeä ‑pikakomento poistettu. Voit vähentää kirkkautta tavallisesta kirkkauspalkista."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Yhteydet"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Saavutettavuus"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Apusovellukset"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Yksityisyys"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Sovellusten tarjoama"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Näyttö"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tuntematon"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index ecb17f9..95d7707 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ajouter à une note"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Inclure le lien"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Des liens ne peuvent pas être ajoutés à partir d\'autres profils"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement d\'écran"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Ajouter"</string>
<string name="manage_users" msgid="1823875311934643849">"Gérer utilisateurs"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Cette notification ne prend pas en charge l\'écran partagé par glissement"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi non disponible"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode priorité"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"L\'alarme a été réglée"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personn. l\'écran de verrouillage"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Déverrouiller pour personnaliser l\'écran de verrouillage"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non accessible"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Appareil photo bloqué"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Appareil photo et microphone bloqués"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microphone bloqué"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Apprenez les gestes du pavé tactile, les raccourcis-clavier et bien plus encore"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geste de retour"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Geste d\'accès à l\'écran d\'accueil"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Touche d\'action"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pour revenir en arrière, balayez vers la gauche ou la droite en utilisant trois doigts n\'importe où sur le pavé tactile.\n\nVous pouvez également utiliser le raccourci clavier Action+Échap."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pour accéder à votre écran d\'accueil à tout moment, balayez l\'écran du bas vers le haut avec trois doigts."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bien!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Vous avez appris le geste de retour à l\'écran d\'accueil."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Touche d\'action"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pour accéder à vos applis, appuyez sur la touche d\'action de votre clavier."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Félicitations!"</string>
@@ -1434,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Balayez l\'écran vers le haut avec trois doigts et maintenez-les en place. Touchez pour apprendre d\'autres gestes."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Utiliser votre clavier pour afficher toutes les applis"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Appuyez sur la touche d\'action à tout moment. Touchez pour apprendre d\'autres gestes."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"La réduction supplémentaire de la luminosité fait désormais partie de la barre de luminosité"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Vous pouvez désormais rendre l\'écran encore plus sombre en réduisant davantage le niveau de luminosité à partir du haut de l\'écran.\n\nCela fonctionne mieux lorsque vous êtes dans un environnement sombre."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Retirer le raccourci de réduction supplémentaire de la luminosité"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Le raccourci de réduction supplémentaire de la luminosité à été retiré. Pour réduire la luminosité, utilisez la barre de luminosité habituelle."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index c023f1b..ee0f987 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ajouter à la note"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Inclure le lien"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Impossible d\'ajouter des liens depuis d\'autres profils"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement de l\'écran"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Ajouter"</string>
<string name="manage_users" msgid="1823875311934643849">"Gérer utilisateurs"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Impossible de faire glisser cette notification vers l\'écran partagé"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponible"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode Prioritaire"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme réglée"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personnaliser écran verrouillage"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Déverrouillez pour personnaliser l\'écran de verrouillage"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponible"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Caméra bloquée"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micro bloqué"</string>
@@ -1393,21 +1396,16 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
- <!-- no translation found for launch_keyboard_tutorial_notification_title (8849933155160522519) -->
- <skip />
- <!-- no translation found for launch_keyboard_tutorial_notification_content (2880339951512757918) -->
- <skip />
- <!-- no translation found for launch_touchpad_tutorial_notification_title (2243780062772196901) -->
- <skip />
- <!-- no translation found for launch_touchpad_tutorial_notification_content (7931085031240753226) -->
- <skip />
- <!-- no translation found for launch_keyboard_touchpad_tutorial_notification_title (1940023776496198762) -->
- <skip />
- <!-- no translation found for launch_keyboard_touchpad_tutorial_notification_content (1780725168171929365) -->
- <skip />
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviguer à l\'aide du clavier"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Découvrir les raccourcis clavier"</string>
+ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviguer à l\'aide de votre pavé tactile"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Découvrir les gestes au pavé tactile"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviguer à l\'aide de votre clavier et de votre pavé tactile"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Découvrir les gestes au pavé tactile, les raccourcis clavier et plus encore"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geste Retour"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Geste Accueil"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Touche d\'action"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"OK"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Retour"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pour revenir en arrière, balayez vers la gauche ou vers la droite avec trois doigts n\'importe où sur le pavé tactile.\n\nVous pouvez aussi utiliser le raccourci clavier Action+Échap pour cela."</string>
@@ -1417,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pour accéder à l\'écran d\'accueil à tout moment, balayez l\'écran du bas vers le haut avec trois doigts."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bravo !"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Vous avez appris le geste pour revenir à l\'écran d\'accueil."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Touche d\'action"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pour accéder à vos applis, appuyez sur la touche d\'action de votre clavier."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Félicitations !"</string>
@@ -1440,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Balayez vers le haut en utilisant trois doigts et maintenez. Appuyez pour apprendre d\'autres gestes."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Utilisez votre clavier pour afficher toutes les applis"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Appuyez sur la touche d\'action à tout moment. Appuyez pour apprendre d\'autres gestes."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Luminosité ultra-réduite fait désormais partie de la barre de luminosité"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Désormais, vous pouvez rendre l\'écran encore plus sombre en abaissant davantage le niveau de luminosité en haut de l\'écran.\n\nCela fonctionne mieux lorsque vous êtes dans un environnement sombre."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Supprimer le raccourci Luminosité ultra-réduite"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Raccourci Luminosité ultra-réduite supprimé. Pour diminuer la luminosité, utilisez la barre de luminosité habituelle."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index b525bb8..9214095 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Engadir a unha nota"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Incluír ligazón"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Non se poden engadir ligazóns desde outros perfís"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Gravadora da pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación de actividade en curso sobre unha sesión de gravación de pantalla"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Engadir"</string>
<string name="manage_users" msgid="1823875311934643849">"Usuarios"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificación non pode arrastrarse á pantalla dividida"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A wifi non está dispoñible"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarma definida"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar pantalla de bloqueo"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Para personalizar a pantalla de bloqueo, primeiro desbloquea o dispositivo"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi non dispoñible"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"A cámara está bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"A cámara e o micrófono están bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"O micrófono está bloqueado"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprende a usar os xestos do panel táctil, atallos de teclado e moito máis"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Xesto para volver"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Xesto para ir ao inicio"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tecla de acción"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Feito"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Volver"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para retroceder, pasa tres dedos cara á esquerda ou cara á dereita en calquera parte do panel táctil.\n\nTamén podes usar o atallo de teclado Acción + Escape."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para ir á pantalla de inicio, pasa tres dedos cara arriba desde a parte inferior da pantalla."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Excelente!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Completaches o xesto de ir ao inicio."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de acción"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acceder ás aplicacións, preme a tecla de acción do teclado."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Pasa tres dedos cara arriba e mantenos premidos. Toca para obter máis información sobre os xestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa o teclado para ver todas as aplicacións"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Preme a tecla de acción cando queiras. Toca para obter máis información sobre os xestos."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"A atenuación extra agora está incluída na barra de brillo"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Agora podes aumentar a atenuación da pantalla: só tes que baixar o nivel de brillo aínda máis desde a parte superior.\n\nEsta opción funciona mellor se estás nun ambiente escuro."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Quitar atallo de atenuación extra"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Quitouse o atallo de atenuación extra. Para reducir o brillo, usa a barra de brillo normal."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividade"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accesibilidade"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilidades"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacidade"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Provenientes de aplicacións"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Visualización"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Categoría descoñecida"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 9afbf8e..f4de6ca 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"ઉમેરો"</string>
<string name="manage_users" msgid="1823875311934643849">"વપરાશકર્તાઓને મેનેજ કરો"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"આ નોટિફિકેશન તેને વિભાજિત સ્ક્રીનમાં ખેંચવાની સુવિધાને સપોર્ટ કરતું નથી"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"પ્રાધાન્યતા મોડ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"અલાર્મ સેટ"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"લૉક સ્ક્રીન કસ્ટમાઇઝ કરો"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"લૉક સ્ક્રીનને કસ્ટમાઇઝ કરવા માટે અનલૉક કરો"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"વાઇ-ફાઇ ઉપલબ્ધ નથી"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"કૅમેરા બ્લૉક કરેલો છે"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"કૅમેરા અને માઇક્રોફોન બ્લૉક કરેલા છે"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"માઇક્રોફોન બ્લૉક કરેલો છે"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ટચપૅડના સંકેતો અને કીબોર્ડના શૉર્ટકટ જેવું બીજું ઘણું જાણો"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"પાછળ જવાનો સંકેત"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"હોમ સ્ક્રીન પર જવાનો સંકેત"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ઍક્શન કી"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"થઈ ગયું"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"પાછા જાઓ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"પાછા જવા માટે, ટચપૅડ પર ગમે ત્યાં ત્રણ આંગળી વડે ડાબે અથવા જમણે સ્વાઇપ કરો.\n\nઆના માટે તમે કીબોર્ડ શૉર્ટકટ Action + ESCનો ઉપયોગ કરી શકો છો."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"કોઈપણ સમયે તમારી હોમ સ્ક્રીન પર જવા માટે, ત્રણ આંગળી વડે તમારી સ્ક્રીનની સૌથી નીચેની બાજુએથી ઉપરની તરફ સ્વાઇપ કરો."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"સરસ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"તમે હોમ સ્ક્રીન પર જવાનો સંકેત પૂર્ણ કર્યો છે."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ઍક્શન કી"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"તમારી ઍપ ઍક્સેસ કરવા માટે, તમારા કીબોર્ડ પરની ઍક્શન કી દબાવો."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"અભિનંદન!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ત્રણ આંગળીઓનો ઉપયોગ કરીને ઉપર સ્વાઇપ કરો અને દબાવી રાખો. સંકેતો વિશે વધુ જાણવા માટે ટૅપ કરો."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"બધી ઍપ જોવા માટે તમારા કીબોર્ડનો ઉપયોગ કરો"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"કોઈપણ સમયે ઍક્શન કી દબાવો. સંકેતો વિશે વધુ જાણવા માટે ટૅપ કરો."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"બ્રાઇટનેસ બાર હવે એક્સ્ટ્રા ડિમનો ભાગ છે"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"તમે હવે તમારી સ્ક્રીનના સૌથી ઉપરના ભાગમાંથી બ્રાઇટનેસ લેવલને હજી પણ ઘટાડીને સ્ક્રીનને એક્સ્ટ્રા ડિમ બનાવી શકો છો.\n\nતમે ડાર્ક વાતાવરણમાં હો, ત્યારે આ શ્રેષ્ઠ રીતે કામ કરે છે."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"એક્સ્ટ્રા ડિમ શૉર્ટકટ કાઢી નાખો"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"એક્સ્ટ્રા ડિમ શૉર્ટકટ કાઢી નાખ્યો. તમારી બ્રાઇટનેસ ઘટાડવા માટે, નિયમિત બ્રાઇટનેસ બારનો ઉપયોગ કરો."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"કનેક્ટિવિટી"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ઍક્સેસિબિલિટી"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"યુટિલિટી"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"પ્રાઇવસી"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ઍપ દ્વારા પ્રદાન કરવામાં આવેલી"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ડિસ્પ્લે"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"અજાણ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 2b28b7a..b9af773 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -253,7 +253,7 @@
<string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN चालू."</string>
<string name="accessibility_battery_level" msgid="5143715405241138822">"<xliff:g id="NUMBER">%d</xliff:g> प्रतिशत बैटरी."</string>
<string name="accessibility_battery_level_with_estimate" msgid="6548654589315074529">"बैटरी <xliff:g id="PERCENTAGE">%1$d</xliff:g> प्रतिशत चार्ज है, जो कि <xliff:g id="TIME">%2$s</xliff:g> चल जाएगी"</string>
- <string name="accessibility_battery_level_charging" msgid="8892191177774027364">"बैटरी चार्ज हो रही है, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> प्रतिशत."</string>
+ <string name="accessibility_battery_level_charging" msgid="8892191177774027364">"बैटरी चार्ज हो रही है, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>%%."</string>
<string name="accessibility_battery_level_charging_paused" msgid="3560711496775146763">"बैटरी <xliff:g id="PERCENTAGE">%d</xliff:g> प्रतिशत चार्ज हुई. बैटरी खराब होने से बचाने के लिए, चार्जिंग रोक दी गई है."</string>
<string name="accessibility_battery_level_charging_paused_with_estimate" msgid="2223541217743647858">"बैटरी <xliff:g id="PERCENTAGE">%1$d</xliff:g> प्रतिशत चार्ज हुई, जो कि <xliff:g id="TIME">%2$s</xliff:g> चल जाएगी. बैटरी खराब होने से बचाने के लिए, चार्जिंग रोक दी गई है."</string>
<string name="accessibility_overflow_action" msgid="8555835828182509104">"पूरी सूचनाएं देखें"</string>
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"जोड़ें"</string>
<string name="manage_users" msgid="1823875311934643849">"उपयोगकर्ताओं को मैनेज करें"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"इस सूचना को स्प्लिट स्क्रीन मोड में, खींचा और छोड़ा नहीं जा सकता"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"वाई-फ़ाई उपलब्ध नहीं है"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट किया गया"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"लॉक स्क्रीन को पसंद के मुताबिक बनाएं"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"लॉक स्क्रीन को पसंद के मुताबिक बनाने के लिए अनलॉक करें"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाई-फ़ाई उपलब्ध नहीं है"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कैमरे का ऐक्सेस नहीं है"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कैमरे और माइक्रोफ़ोन का ऐक्सेस नहीं है"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"माइक्रोफ़ोन का ऐक्सेस नहीं है"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचपैड पर हाथ के जेस्चर, कीबोर्ड शॉर्टकट वगैरह के बारे में जानें"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"पीछे जाने का जेस्चर"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम स्क्रीन पर जाने का जेस्चर"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ऐक्शन बटन"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"हो गया"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"वापस जाएं"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"वापस जाने के लिए, टचपैड पर कहीं भी तीन उंगलियों से दाईं या बाईं ओर स्वाइप करें.\n\nइसके अलावा, ऐसा करने के लिए Action + ESC बटन का भी इस्तेमाल किया जा सकता है."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"किसी भी समय फ़ोन की होम स्क्रीन पर जाने के लिए, तीन उंगलियों से फ़ोन पर सबसे नीचे से ऊपर की ओर स्वाइप करें."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"बढ़िया!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"आपने जान लिया कि हाथ का जेस्चर इस्तेमाल करके, होम स्क्रीन पर कैसे जाएं."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ऐक्शन बटन"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"अपने ऐप्लिकेशन ऐक्सेस करने के लिए, कीबोर्ड पर ऐक्शन बटन दबाएं."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"बधाई हो!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"तीन उंगलियों से ऊपर की ओर स्वाइप करें और दबाकर रखें. जेस्चर की ज़्यादा जानकारी पाने के लिए टैप करें."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"सभी ऐप्लिकेशन देखने के लिए, कीबोर्ड का इस्तेमाल करें"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"किसी भी समय ऐक्शन बटन दबाएं. हाथ के जेस्चर के बारे में ज़्यादा जानने के लिए टैप करें."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा, अब ब्राइटनेस बार का हिस्सा है"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"अब स्क्रीन के सबसे ऊपरी हिस्से से, स्क्रीन की रोशनी सामान्य लेवल से और कम की जा सकती है.\n\nयह सुविधा, अंधेरे वाली जगह पर बेहतर तरीके से काम करती है."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा का शॉर्टकट हटाएं"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा का शॉर्टकट हटा दिया गया. स्क्रीन की रोशनी कम करने के लिए, ब्राइटनेस बार का इस्तेमाल करें."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"कनेक्टिविटी"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"सुलभता"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"काम की सेवाएं"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"निजता"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ऐप्लिकेशन से मिली जानकारी"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"डिसप्ले"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"कोई जानकारी नहीं है"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 34bccbd..c34c07e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj bilješci"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Uključi vezu"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Veze se ne mogu dodati s drugih profila"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Snimač zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrada snimanja zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Tekuća obavijest za sesiju snimanja zaslona"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljanje korisnicima"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Ova obavijest ne podržava povlačenje na podijeljeni zaslon."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nije dostupan"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetni način rada"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je postavljen"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Prilagodite zaključavanje zaslona"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Otključajte da biste prilagodili zaključani zaslon"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nije dostupan"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokirana"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Blokirani su kamera i mikrofon"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Saznajte više o pokretima za dodirnu podlogu, tipkovnim prečacima i ostalom"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Pokret za povratak"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pokret za otvaranje početnog zaslona"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tipka za radnju"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotovo"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Natrag"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Da biste se vratili natrag, s tri prsta prijeđite ulijevo ili udesno bilo gdje na dodirnoj podlozi.\n\nZa to možete upotrijebiti i tipku za radnju tipkovnog prečaca + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Da biste u bilo kojem trenutku otvorili početni zaslon, trima prstima prijeđite prema gore od dna zaslona."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Odlično!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Izvršili ste pokret za otvaranje početnog zaslona."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka za radnju"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Da biste pristupili svojim aplikacijama, pritisnite tipku za radnje na tipkovnici."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Prijeđite prema gore trima prstima i zadržite pritisak. Dodirnite da biste naučili više pokreta."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Upotrijebite tipkovnicu za prikaz svih aplikacija"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pritisnite tipku za radnju u bilo kojem trenutku. Dodirnite da biste naučili više pokreta."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Dodatno zatamnjenje sada je dio trake za svjetlinu"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Zaslon možete dodatno zatamniti daljnjim smanjivanjem razine svjetline na vrhu zaslona.\n\nTo najbolje funkcionira kada ste u tamnom okruženju."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Ukloni prečac za dodatno zatamnjenje"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Prečac za dodatno zatamnjenje je uklonjen. Da biste smanjili svjetlinu, upotrijebite regularnu traku za svjetlinu."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Povezivost"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pristupačnost"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Uslužni programi"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privatnost"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Pružaju aplikacije"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Prikaz"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index cc2f66e..abc7bd0 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Hozzáadás jegyzethez"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Linkkel együtt"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Más profilokból nem lehet linkeket hozzáadni"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Képernyőrögzítő"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Képernyőrögzítés feldolgozása"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Folyamatban lévő értesítés képernyőrögzítési munkamenethez"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Hozzáadás"</string>
<string name="manage_users" msgid="1823875311934643849">"Kezelés"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Az értesítés nem támogatja az osztott képernyőre való áthúzást."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A Wi‑Fi nem áll rendelkezésre"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritás mód"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ébresztő beállítva"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Lezárási képernyő testreszabása"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Oldja fel a zárolást a lezárási képernyő testreszabásához"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Nem áll rendelkezésre Wi-Fi"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera letiltva"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera és mikrofon letiltva"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon letiltva"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Érintőpad-kézmozdulatok, billentyűparancsok és egyebek megismerése"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Vissza kézmozdulat"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Kezdőképernyő kézmozdulat"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Műveletbillentyű"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kész"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Vissza"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"A visszalépéshez csúsztasson három ujjal balra vagy a jobbra az érintőpadon.\n\nEnnek végrehajtásához használhatja az Action + Esc billentyűparancsot is."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ha bármikor vissza szeretne térni a kezdőképernyőre, csúsztassa gyorsan felfelé három ujját a képernyő aljáról."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Remek!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Teljesítette a kezdőképernyőre lépés kézmozdulatát."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Műveletbillentyű"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Az alkalmazásokhoz való hozzáféréshez nyomja meg a billentyűzet műveletbillentyűjét."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulálunk!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Gyúsztason felfelé három ujjal, és tartsa lenyomva az ujjait. Koppintson a további kézmozdulatokért."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"A billentyűzet használatával valamennyi alkalmazás megtekinthető"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"A műveletbillentyű bármikor használható. Koppintson a további kézmozdulatokért."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Az extrasötét funkció mostantól része a fényerő-beállítási sávnak"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"A képernyő tetején mostantól extrasötétre állíthatja a képernyőt, amivel a korábbinál még jobban csökkentheti a fényerőt.\n\nA funkció sötét környezetben használható a legjobban."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Az extrasötét funkció gyorsparancsának eltávolítása"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Eltávolította az extrasötét funkció gyorsparancsát. A fényerő csökkentéséhez használja a fényerő-beállítási sávot."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Kapcsolódás"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Kisegítő lehetőségek"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Segédprogramok"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Adatvédelem"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Alkalmazás által biztosított"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Kijelző"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ismeretlen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index c017263..d25cb52 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ավելացնել նշմանը"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Ներառել հղումը"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Այլ պրոֆիլներից հնարավոր չէ հղումներ ավելացնել"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Էկրանի տեսագրում"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Ավելացնել"</string>
<string name="manage_users" msgid="1823875311934643849">"Կառավարել"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Այս ծանուցումը հնարավոր չէ քաշել տրոհված էկրանի մեկ հատվածից մյուսը"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi-ը հասանելի չէ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Առաջնահերթության ռեժիմ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Զարթուցիչը դրված է"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Անհատականացնել կողպէկրանը"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ապակողպեք սարքը՝ կողպէկրանը կարգավորելու համար"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ցանց հասանելի չէ"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Տեսախցիկն արգելափակված է"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Տեսախցիկն ու խոսափողը արգելափակված են"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Խոսափողն արգելափակված է"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Սովորեք օգտագործել հպահարթակի ժեստերը, ստեղնային դյուրանցումները և ավելին"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"«Հետ» ժեստ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Հիմնական էկրան անցնելու ժեստ"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Գործողության ստեղն"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Պատրաստ է"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Հետ գնալ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Հետ գնալու համար հպահարթակի վրա երեք մատով սահեցրեք ձախ կամ աջ։\n\nԻնչպես նաև կարող եք օգտագործել ստեղնային դյուրանցման գործողությունը + Esc։"</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Հիմնական էկրան վերադառնալու համար երեք մատը էկրանի ներքևից սահեցրեք վերև։"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Գերազանց է"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Դուք սովորեցիք հիմնական էկրան անցնելու ժեստը։"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Գործողության ստեղն"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Բոլոր հավելվածներն օգտագործելու համար սեղմեք գործողության ստեղնը ստեղնաշարի վրա"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Շնորհավո՛ր"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Երեք մատը սահեցրեք վերև և սեղմած պահեք։ Հպեք՝ ավելի շատ ժեստերի ծանոթանալու համար։"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Օգտագործեք ձեր ստեղնաշարը՝ բոլոր հավելվածները դիտելու համար"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Ցանկացած ժամանակ սեղմեք գործողության ստեղնը։ Հպեք՝ ավելի շատ ժեստերի ծանոթանալու համար։"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Հավելյալ խամրեցումն այժմ պայծառության գոտում է"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Էկրանը հավելյալ խամրեցնելու համար բացեք կարգավորումները էկրանի վերևի մասից։\n\nԽորհուրդ ենք տալիս օգտագործել այս գործառույթը, երբ շուրջը մութ է։"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Հեռացնել հավելյալ խամրեցման դյուրանցումը"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Հավելյալ խամրեցման դյուրանցումը հեռացվեց։ Պայծառության մակարդակը նվազեցնելու համար օգտագործեք պայծառության գոտին։"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Կապ"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Հատուկ գործառույթներ"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Կոմունալ ծառայություններ"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Գաղտնիություն"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Տրամադրվել են հավելվածների կողմից"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Էկրան"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Անհայտ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index a3ea9b2..bf1085d 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Tambahkan ke catatan"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Sertakan link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Link tidak dapat ditambahkan dari profil lain"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Perekam Layar"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses perekaman layar"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifikasi yang sedang berjalan untuk sesi rekaman layar"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Tambahkan"</string>
<string name="manage_users" msgid="1823875311934643849">"Kelola pengguna"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Notifikasi ini tidak mendukung fitur tarik ke layar terpisah"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi tidak tersedia"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mode prioritas"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm disetel"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Sesuaikan layar kunci"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Buka kunci untuk menyesuaikan layar kunci"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi tidak tersedia"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera diblokir"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon diblokir"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon diblokir"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Pelajari gestur touchpad, pintasan keyboard, dan lainnya"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gestur kembali"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gestur layar utama"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tombol tindakan"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Untuk kembali, geser ke kiri atau kanan menggunakan tiga jari di touchpad.\n\nAnda juga dapat menggunakan pintasan keyboard Action + ECS untuk melakukannya."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Untuk membuka layar utama kapan saja, geser ke atas menggunakan tiga jari dari bawah layar Anda."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bagus!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Anda telah menyelesaikan gestur buka layar utama."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tombol tindakan"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Untuk mengakses aplikasi, tekan tombol tindakan di keyboard."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Selamat!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Geser ke atas dan tahan menggunakan tiga jari. Ketuk untuk mempelajari gestur lainnya."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gunakan keyboard untuk melihat semua aplikasi"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tekan tombol tindakan kapan saja. Ketuk untuk mempelajari gestur lainnya."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Ekstra redup kini menjadi bagian dari panel kecerahan"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Anda kini dapat membuat layar menjadi ekstra redup dengan menurunkan tingkat kecerahan lebih banyak lagi dari bagian atas layar.\n\nFitur ini berfungsi optimal saat Anda berada di tempat yang gelap."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Hapus pintasan ekstra redup"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Pintasan ekstra redup dihapus. Untuk menurunkan kecerahan, gunakan panel kecerahan biasa."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Konektivitas"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Aksesibilitas"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitas"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privasi"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Disediakan oleh aplikasi"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Tampilan"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tidak diketahui"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 2468bcc..987a51d 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Bæta við"</string>
<string name="manage_users" msgid="1823875311934643849">"Stjórna notendum"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Þessi tilkynning styður ekki að draga yfir á skiptan skjá."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi ekki tiltækt"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Forgangsstilling"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Vekjari stilltur"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Sérsníða lásskjá"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Taktu úr lás til að sérsníða lásskjá"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi er ekki til staðar"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Lokað fyrir myndavél"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Lokað fyrir myndavél og hljóðnema"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Lokað fyrir hljóðnema"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Kynntu þér bendingar á snertifleti, flýtilykla og fleira"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Bending til að fara til baka"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Bending til að fara á upphafsskjá"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Aðgerðalykill"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Lokið"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Til baka"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Strjúktu til vinstri eða hægri með þremur fingrum hvar sem er á snertifletinum til að fara til baka.\n\nÞú getur einnig notað flýtileiðaraðgerðina + ESC til að gera þetta."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Strjúktu upp frá neðri brún skjásins með þremur fingrum til að opna heimaskjáinn."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Flott!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Þú laukst við að kynna þér bendinguna „heim“."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Aðgerðalykill"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ýttu á aðgerðalykilinn á lyklaborðinu til að opna forritin þín."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Til hamingju!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Strjúktu upp og haltu með þremur fingrum. Ýttu til að læra fleiri bendingar."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Notaðu lyklaborðið til að sjá öll forrit"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Ýttu hvenær sem er á aðgerðalykilinn. Ýttu til að læra fleiri bendingar."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Nú er stillingin „mjög dökkt“ hluti af birtustigsstikunni"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Nú geturðu gert skjáinn mjög dökkan með því að lækka birtustigið enn frekar efst á skjánum.\n\nÞetta virkar best þegar umhverfi þitt er mjög dimmt."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Fjarlægja flýtilykil á mjög dökka stillingu"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Flýtilykill á mjög dökka stillingu fjarlægður. Notaðu hefðbundnu birtustigsstikuna til að lækka birtustigið."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Tengigeta"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Aðgengileiki"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Aukabúnaður"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Persónuvernd"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Frá forritum"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Skjár"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Óþekkt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5ea4486..e2733b1 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Aggiungi alla nota"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Includi link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Impossibile aggiungere link da altri profili"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Registrazione dello schermo"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaborazione registrazione…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifica costante per una sessione di registrazione dello schermo"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Aggiungi"</string>
<string name="manage_users" msgid="1823875311934643849">"Gestisci utenti"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Non è possibile trascinare questa notifica tra le due parti dello schermo diviso"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi non disponibile"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modalità Priorità"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Sveglia impostata"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizza schermata di blocco"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Sblocca per personalizzare la schermata di blocco"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponibile"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Videocamera bloccata"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Videocamera e microfono bloccati"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfono bloccato"</string>
@@ -1393,21 +1396,16 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona Espandi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oppure"</string>
- <!-- no translation found for launch_keyboard_tutorial_notification_title (8849933155160522519) -->
- <skip />
- <!-- no translation found for launch_keyboard_tutorial_notification_content (2880339951512757918) -->
- <skip />
- <!-- no translation found for launch_touchpad_tutorial_notification_title (2243780062772196901) -->
- <skip />
- <!-- no translation found for launch_touchpad_tutorial_notification_content (7931085031240753226) -->
- <skip />
- <!-- no translation found for launch_keyboard_touchpad_tutorial_notification_title (1940023776496198762) -->
- <skip />
- <!-- no translation found for launch_keyboard_touchpad_tutorial_notification_content (1780725168171929365) -->
- <skip />
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Naviga usando la tastiera"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Informazioni sulle scorciatoie da tastiera"</string>
+ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Naviga usando il touchpad"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Impara i gesti con il touchpad"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Naviga usando la tastiera e il touchpad"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Scopri gesti con il touchpad, scorciatoie da tastiera e altro ancora"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto Indietro"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto Home"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tasto azione"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Fine"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Indietro"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Per tornare indietro, scorri verso sinistra o verso destra utilizzando tre dita in un punto qualsiasi del touchpad.\n\nPuoi usare anche la scorciatoia da tastiera Action + Esc per farlo."</string>
@@ -1417,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Per andare alla schermata Home, scorri verso l\'alto con tre dita dalla parte inferiore dello schermo."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bene!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Hai completato il gesto Vai alla schermata Home."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasto azione"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Per accedere alle tue app, premi il tasto azione sulla tastiera."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Complimenti!"</string>
@@ -1440,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Scorri verso l\'alto e tieni premuto con tre dita. Tocca per scoprire altri gesti."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Usa la tastiera per visualizzare tutte le app"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Premi il tasto azione in qualsiasi momento. Tocca per scoprire altri gesti."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Ora l\'attenuazione extra è nella barra della luminosità"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Ora puoi usare l\'attenuazione extra per lo schermo abbassando il livello di luminosità ancora di più dalla parte superiore della schermata.\n\nQuesta funzionalità opera in modo ottimale quando ti trovi in un ambiente buio."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Rimuovi scorciatoia attenuazione extra"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Scorciatoia attenuazione extra rimossa. Per diminuire la luminosità, usa la normale barra della luminosità."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 5fd5ca6..2a006a8 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"הוספה לפתק"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"הכנסת הקישור"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"לא ניתן להוסיף קישורים מפרופילים אחרים"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"מקליט המסך"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"הוספה"</string>
<string name="manage_users" msgid="1823875311934643849">"ניהול משתמשים"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ההתראה הזו לא תומכת בגרירה למסך מפוצל"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi לא זמין"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"מצב עדיפות"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ההתראה מוגדרת"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"התאמה אישית של מסך הנעילה"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"כדי להתאים אישית את מסך הנעילה, יש לבטל את הנעילה"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ה-Wi-Fi לא זמין"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"המצלמה חסומה"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"המצלמה והמיקרופון חסומים"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"המיקרופון חסום"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"מידע על התנועות בלוח המגע, מקשי קיצור ועוד"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"תנועת חזרה"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"תנועת חזרה למסך הבית"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"מקש הפעולה"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"סיום"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"חזרה"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"כדי לחזור אחורה, מחליקים שמאלה או ימינה עם שלוש אצבעות בכל מקום על לוח המגע.\n\nאפשר לבצע את הפעולה הזו גם באמצעות קיצור הדרך לפעולה + מקש ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"כדי לעבור למסך הבית בכל שלב, צריך להחליק למעלה עם שלוש אצבעות מהחלק התחתון של המסך."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"איזה יופי!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"השלמת את תנועת המעבר למסך הבית."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"מקש הפעולה"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"כדי לגשת לאפליקציות, מקישים על מקש הפעולה במקלדת."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"כל הכבוד!"</string>
@@ -1434,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"מחליקים למעלה ולוחצים לחיצה ארוכה עם שלוש אצבעות. ניתן להקיש כדי לקבל מידע נוסף על התנועות."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"איך להשתמש במקלדת כדי לראות את כל האפליקציות"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"בכל שלב אפשר ללחוץ על מקש הפעולה. ניתן להקיש כדי לקבל מידע נוסף על התנועות."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"התכונה \'מעומעם במיוחד\' נוספה לסרגל הבהירות"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"עכשיו אפשר להפוך את המסך למעומעם במיוחד באמצעות הפחתה נוספת של רמת הבהירות דרך החלק העליון במסך.\n\nהפעולה הזו עובדת הכי טוב בסביבה חשוכה."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"הסרה של קיצור הדרך לתכונה \'מעומעם במיוחד\'"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"קיצור הדרך לתכונה \'מעומעם במיוחד\' הוסר. כדי להפחית את הבהירות, אפשר להשתמש בסרגל הבהירות הרגיל."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7897f48..780254f 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"追加"</string>
<string name="manage_users" msgid="1823875311934643849">"ユーザーの管理"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"この通知は、分割画面へのドラッグをサポートしていません"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi を利用できません"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先順位モード"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"アラームを設定しました"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ロック画面のカスタマイズ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ロック画面をカスタマイズするにはロックを解除してください"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi は利用できません"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"カメラはブロックされています"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"カメラとマイクはブロックされています"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"マイクはブロックされています"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"タッチパッド操作やキーボード ショートカットなどの詳細"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"「戻る」ジェスチャー"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"「ホーム」ジェスチャー"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"アクションキー"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完了"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"戻る"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"戻るには、3 本の指でタッチパッドを左右にスワイプします。\n\nキーボード ショートカットのアクション + ESC キーを使用して、この操作を行うこともできます。"</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"3 本の指で画面を下から上にスワイプすると、ホーム画面にいつでも移動できます。"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"お疲れさまでした。"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"「ホームに移動」操作を学習しました。"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"アクションキー"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"アプリにアクセスするには、キーボードのアクションキーを押します。"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"お疲れさまでした。"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"3 本の指で上にスワイプして長押しします。ジェスチャーの詳細を確認するにはタップしてください。"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"キーボードを使用して、すべてのアプリを表示する"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"アクションキーを押せばいつでも機能します。ジェスチャーの詳細を確認するにはタップしてください。"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"「さらに輝度を下げる」機能が明るさのバーの追加されました"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"画面の上部で明るさを大幅に低く設定することで、画面の輝度をさらに下げられるようになりました。\n\nこの設定は暗い場所での操作に最適です。"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"「さらに輝度を下げる」のショートカットを削除する"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"「さらに輝度を下げる」のショートカットを削除しました。明るさを下げるには、通常の明るさのバーを使用してください。"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"接続"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ユーザー補助"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ユーティリティ"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"プライバシー"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"アプリから提供"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ディスプレイ"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 5550a63..dab2619 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"დამატება"</string>
<string name="manage_users" msgid="1823875311934643849">"მართვა"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ამ შეტყობინების გადათრევა გაყოფილ ეკრანებს შორის არ არის მხარდაჭერილი."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi მიუწვდომელია"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"პრიორიტეტული რეჟიმი"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"მაღვიძარა დაყენებულია"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ჩაკეთილი ეკრანის მორგება"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ჩაკეტილი ეკრანის მოსარგებად გაბლოკეთ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi მიუწვდომელია"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"კამერა დაბლოკილია"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"კამერა და მიკროფონი დაბლოკილია"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"მიკროფონი დაბლოკილია"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"სენსორული პანელის ჟესტების, კლავიატურის მალსახმობების და სხვა ფუნქციების სწავლა"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"უკან დაბრუნების ჟესტი"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"მთავარ ეკრანზე გადასვლის ჟესტი"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"მოქმედების კლავიში"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"მზადაა"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"უკან დაბრუნება"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"უკან დასაბრუნებლად სენსორულ პანელზე გადაფურცლეთ მარცხნივ ან მარჯვნივ სამი თითის გამოყენებით ნებისმიერ ადგილას.\n\nამისთვის თქვენ ასევე შეგიძლიათ გამოიყენოთ კლავიატურის მალსახმობის მოქმედება + ESC."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"თქვენს მთავარ ეკრანზე ნებისმიერ დროს გადასასვლელად გადაფურცლეთ ეკრანის ქვემოდან ზემოთ სამი თითით."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"მშვენიერია!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"თქვენ შეასრულეთ მთავარ ეკრანზე დაბრუნების ჟესტი."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"მოქმედების კლავიში"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"აპებზე წვდომისთვის დააჭირეთ მოქმედების კლავიშს თქვენს კლავიატურაზე."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"გილოცავთ!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"სამი თითით გადაფურცლეთ ზემოთ და მოიცადეთ. შეეხეთ მეტი ჟესტის შესასწავლად."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ყველა აპის სანახავად გამოიყენეთ თქვენი კლავიატურა"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ნებისმიერ დროს დააჭირეთ მოქმედების კლავიშს. შეეხეთ მეტი ჟესტის შესასწავლად."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"დამატებითი დაბინდვის ფუქნცია ახლა განთავსებულია სიკაშკაშის პანელზე"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ახლა თქვენ შეგიძლიათ დამატებით დაბინდოთ ეკრანი მის ზედა ნაწილში სიკაშკაშის დონის კიდევ უფრო შემცირების გზით.\n\nეს ყველაზე უკეთ ბნელ გარემოში ყოფნისას მუშაობს."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"დამატებითი დაბინდვის მალსახმობის ამოშლა"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"დამატებითი დაბინდვის მალსახმობი ამოშლილია. სიკაშკაშის შესამცირებლად გამოიყენეთ სიკაშკაშის ჩვეულებრივი პანელი."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"კავშირი"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"მარტივი წვდომა"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ხელსაწყოები"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"კონფიდენციალურობა"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"მოწოდებულია აპების მიერ"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ეკრანი"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"უცნობი"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index d8b4542..53ef57e 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ескертпеге қосу"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Сілтеме қосу"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Сілтемелерді басқа профильдерден қосу мүмкін емес."</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Экран жазғыш"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Қосу"</string>
<string name="manage_users" msgid="1823875311934643849">"Параметрлер"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Бұл хабарландыруды бөлінген экранға сүйреп апару мүмкін емес."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi қолжетімсіз"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Басымдық режимі"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Оятқыш орнатылды"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Құлып экранын бейімдеу"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Құлып экранын бейімдеу үшін құлыпты ашыңыз"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi қолжетімсіз."</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера блокталған."</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера мен микрофон блокталған."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон блокталған."</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Сенсорлық тақта қимылдарын, перне тіркесімдерін және т.б. үйреніңіз."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Артқа қайтару қимылы"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Негізгі бетке қайтару қимылы"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Әрекет пернесі"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Дайын"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артқа"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Артқа қайту үшін сенсорлық тақтаның кез келген жерін үш саусақпен солға не оңға сырғытыңыз.\n\nСондай-ақ Action + ESC перне тіркесімін пайдалануға болады."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Негізгі экранға кез келген уақытта өту үшін экранның төменгі жағынан жоғары қарай үш саусағыңызбен сырғытыңыз."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Жақсы нәтиже!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Негізгі экранға қайту қимылын аяқтадыңыз."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Әрекет пернесі"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Қолданбаларыңызға кіру үшін пернетақтадағы әрекет пернесін басыңыз."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Құттықтаймыз!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Үш саусақпен жоғары сырғытып, басып тұрыңыз. Басқа қимылдарды үйрену үшін түртіңіз."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Барлық қолданбаны көру үшін пернетақтаны қолданыңыз"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Әрекет пернесін кез келген уақытта баса аласыз. Басқа қимылдарды үйрену үшін түртіңіз."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Экранды қарайту функциясын енді жарықтық панелінің бөлшегі болады"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Енді экранның жоғарғы бөлігінде жарықтық деңгейін түсіру арқылы экранды одан сайын қарайтуға болады.\n\nБұл мүмкіндіктің артықшылығын қараңғы жерде көруге болады."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Экранды қарайту жылдам пәрменін өшіру"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Экранды қарайту жылдам пәрмені өшірілді. Жарықтықты азайту үшін әдеттегі жарықтық панелін пайдаланыңыз."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Қосылу мүмкіндігі"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Арнайы мүмкіндіктер"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Утилиталар"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Құпиялық"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Қолданбалар ұсынған"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Дисплей"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгісіз"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index f2fc313..e2bba53 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"បញ្ចូល"</string>
<string name="manage_users" msgid="1823875311934643849">"គ្រប់គ្រងអ្នកប្រើប្រាស់"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ការជូនដំណឹងនេះមិនអាចឱ្យអូសដើម្បីបំបែកអេក្រង់បានទេ"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ត្រូវបានបិទ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"មុខងារអាទិភាព"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"រូបកំណត់ម៉ោងរោទ៍"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ប្ដូរអេក្រង់ចាក់សោតាមបំណង"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ដោះសោ ដើម្បីប្ដូរអេក្រង់ចាក់សោតាមបំណង"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"មិនមាន Wi-Fi ទេ"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"បានទប់ស្កាត់កាមេរ៉ា"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"បានទប់ស្កាត់កាមេរ៉ា និងមីក្រូហ្វូន"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"បានទប់ស្កាត់មីក្រូហ្វូន"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ស្វែងយល់អំពីចលនាផ្ទាំងប៉ះ ផ្លូវកាត់ក្ដារចុច និងអ្វីៗជាច្រើនទៀត"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ចលនាថយក្រោយ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ចលនាទៅទំព័រដើម"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"គ្រាប់ចុចសកម្មភាព"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"រួចរាល់"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ថយក្រោយ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ដើម្បីថយក្រោយ សូមអូសទៅឆ្វេង ឬស្ដាំដោយប្រើម្រាមដៃបីនៅត្រង់ណាក៏បានលើផ្ទាំងប៉ះ។\n\nអ្នកក៏អាចប្រើសកម្មភាពផ្លូវកាត់ក្ដារចុច + ESC សម្រាប់ការធ្វើបែបនេះ។"</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ដើម្បីចូលទៅអេក្រង់ដើមរបស់អ្នកនៅពេលណាក៏បាន សូមអូសឡើងលើដោយប្រើម្រាមដៃបីពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នក។"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ល្អ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"អ្នកបានបញ្ចប់ចលនាចូលទៅកាន់ទំព័រដើមហើយ។"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"គ្រាប់ចុចសកម្មភាព"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ដើម្បីចូលប្រើប្រាស់កម្មវិធីរបស់អ្នក សូមចុចគ្រាប់ចុចសកម្មភាពនៅលើក្ដារចុចរបស់អ្នក។"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"សូមអបអរសាទរ!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"អូសឡើងលើ ហើយសង្កត់ឱ្យជាប់ដោយប្រើម្រាមដៃបី។ ចុច ដើម្បីស្វែងយល់បន្ថែមអំពីចលនា។"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ប្រើក្ដារចុចរបស់អ្នក ដើម្បីមើលកម្មវិធីទាំងអស់"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ចុចគ្រាប់ចុចសកម្មភាពនៅពេលណាក៏បាន។ ចុច ដើម្បីស្វែងយល់បន្ថែមអំពីចលនា។"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"ឥឡូវនេះ មុខងារងងឹតខ្លាំងក្លាយជាផ្នែកមួយនៃរបារពន្លឺ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ឥឡូវនេះ អ្នកអាចធ្វើឱ្យអេក្រង់ងងឹតខ្លាំងបានដោយបន្ថយកម្រិតពន្លឺបន្ថែមទៀតដោយចូលទៅកាន់ផ្នែកខាងលើនៃអេក្រង់របស់អ្នក។\n\nការធ្វើបែបនេះទទួលបានលទ្ធផលប្រសើរបំផុត ពេលអ្នកស្ថិតនៅកន្លែងងងឹត។"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"ដកផ្លូវកាត់មុខងារងងឹតខ្លាំងចេញ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"ផ្លូវកាត់មុខងារងងឹតខ្លាំងត្រូវបានដកចេញ។ ដើម្បីបន្ថយពន្លឺរបស់អ្នក សូមប្រើរបារពន្លឺធម្មតា។"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ការតភ្ជាប់"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ភាពងាយស្រួល"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"កម្មវិធីសម្រួលដំណើរការ"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"ឯកជនភាព"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ផ្ដល់ជូនដោយកម្មវិធី"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ផ្ទាំងបង្ហាញ"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"មិនស្គាល់"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 6f63332..0b87cbb 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"ಸೇರಿಸಿ"</string>
<string name="manage_users" msgid="1823875311934643849">"ಬಳಕೆದಾರರನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡುವುದನ್ನು ಈ ನೋಟಿಫಿಕೇಶನ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ಆದ್ಯತೆ ಮೋಡ್"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ಅಲಾರಾಂ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ವೈ-ಫೈ ಲಭ್ಯವಿಲ್ಲ"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ಕ್ಯಾಮರಾವನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ಟಚ್ಪ್ಯಾಡ್ ಗೆಸ್ಚರ್ಗಳು, ಕೀಬೋರ್ಡ್ಗಳ ಶಾರ್ಟ್ಕಟ್ಗಳು ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ತಿಳಿಯಿರಿ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ಹಿಂಬದಿ ಗೆಸ್ಚರ್"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ಹೋಮ್ ಗೆಸ್ಚರ್"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ಆ್ಯಕ್ಷನ್ ಕೀ"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ಮುಗಿದಿದೆ"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ಹಿಂತಿರುಗಿ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ಹಿಂತಿರುಗಲು, ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ಎಲ್ಲಿಯಾದರೂ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಎಡ ಅಥವಾ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ.\n\nಇದಕ್ಕಾಗಿ ನೀವು ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ Action + ESC ಅನ್ನು ಸಹ ಬಳಸಬಹುದು."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಹೋಗಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಕೆಳಗಿನಿಂದ ಮೂರು ಬೆರಳುಗಳಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ಭೇಷ್!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ಆ್ಯಕ್ಷನ್ ಕೀ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ನಿಮ್ಮ ಆ್ಯಪ್ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು, ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ನಲ್ಲಿರುವ ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಒತ್ತಿರಿ."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ಅಭಿನಂದನೆಗಳು!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ಮೂರು ಬೆರಳುಗಳಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಹಾಗೂ ಹೋಲ್ಡ್ ಮಾಡಿ. ಇನ್ನಷ್ಟು ಗೆಸ್ಚರ್ಗಳನ್ನು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ಯಾವಾಗ ಬೇಕಾದರೂ ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಒತ್ತಿರಿ. ಇನ್ನಷ್ಟು ಗೆಸ್ಚರ್ಗಳನ್ನು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"ಇನ್ನಷ್ಟು ಮಬ್ಬು ಈಗ ಬ್ರೈಟ್ನೆಸ್ ಬಾರ್ನ ಭಾಗವಾಗಿದೆ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಮೇಲ್ಭಾಗದಿಂದ ಬ್ರೈಟ್ನೆಸ್ ಮಟ್ಟವನ್ನು ಇನ್ನಷ್ಟು ಕಡಿಮೆ ಮಾಡುವ ಮೂಲಕ ನೀವು ಈಗ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಇನ್ನಷ್ಟು ಮಬ್ಬುಗೊಳಿಸಬಹುದು.\n\nನೀವು ಕತ್ತಲೆಯ ವಾತಾವರಣದಲ್ಲಿರುವಾಗ ಇದು ಉತ್ತಮವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"ಇನ್ನಷ್ಟು ಮಬ್ಬು ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"ಇನ್ನಷ್ಟು ಮಬ್ಬು ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ. ನಿಮ್ಮ ಬ್ರೈಟ್ನೆಸ್ ಅನ್ನು ಕಡಿಮೆ ಮಾಡಲು, ಸಾಮಾನ್ಯ ಬ್ರೈಟ್ನೆಸ್ ಬಾರ್ ಬಳಸಿ."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ಕನೆಕ್ಟಿವಿಟಿ"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ಯುಟಿಲಿಟಿಗಳು"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"ಗೌಪ್ಯತೆ"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ಆ್ಯಪ್ಗಳಿಂದ ಒದಗಿಸಲಾಗಿದೆ"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ಡಿಸ್ಪ್ಲೇ"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ಅಪರಿಚಿತ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 75bc3b2..4f4c5b9 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"메모에 추가"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"링크 포함"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g><xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"다른 프로필의 링크를 추가할 수 없습니다."</string>
<string name="screenrecord_title" msgid="4257171601439507792">"화면 녹화"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"화면 녹화 처리 중"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"화면 녹화 세션에 관한 지속적인 알림"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"추가"</string>
<string name="manage_users" msgid="1823875311934643849">"사용자 관리"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"드래그하여 화면을 분할하는 기능이 지원되지 않는 알림입니다."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi를 이용할 수 없습니다."</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"우선순위 모드입니다."</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"알람이 설정되었습니다."</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"잠금 화면 맞춤 설정"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"잠금 화면 맞춤설정을 위해 잠금 해제"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi를 사용할 수 없음"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"카메라 차단됨"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"카메라 및 마이크 차단됨"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"마이크 차단됨"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"터치패드 동작, 단축키 등 알아보기"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"뒤로 동작"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"홈 동작"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"작업 키"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"완료"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"뒤로"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"돌아가려면 세 손가락을 사용해 터치패드의 아무 곳이나 왼쪽 또는 오른쪽으로 스와이프합니다.\n\n키보드 단축키 Action + ESC를 사용할 수도 있습니다."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"언제든지 홈 화면으로 이동하려면 세 손가락으로 화면 하단에서 위로 스와이프하세요."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"좋습니다"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"홈으로 이동 동작을 완료했습니다."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"작업 키"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"앱에 액세스하려면 키보드의 작업 키를 누르세요."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"축하합니다"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"세 손가락을 사용해 위로 스와이프한 다음 잠시 기다리세요. 더 많은 동작을 알아보려면 탭하세요."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"키보드를 사용하여 모든 앱 보기"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"언제든지 작업 키를 누릅니다. 더 많은 동작을 알아보려면 탭하세요."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"이제 \'더 어둡게\' 기능이 밝기 막대에 추가되었습니다"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"이제 화면 상단에서 밝기 수준을 더 낮춰 화면을 더 어둡게 만들 수 있습니다\n\n이 기능은 어두운 환경에서 가장 잘 작동합니다."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"\'더 어둡게\' 단축키 삭제"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"\'더 어둡게\' 단축키가 삭제되었습니다. 밝기를 낮추려면 일반 밝기 막대를 사용하세요."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"연결"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"접근성"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"유틸리티"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"개인 정보 보호"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"앱에서 제공"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"디스플레이"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"알 수 없음"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 9bf427c..023d69e 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -243,7 +243,7 @@
<string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Түзмөктүн чоо-жайын конфигурациялоо үчүн чыкылдатыңыз"</string>
<string name="accessibility_bluetooth_device_settings_see_all" msgid="9111952496905423543">"Бардык түзмөктөрдү көрүү үчүн чыкылдатыңыз"</string>
<string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="2435184865793496966">"Жаңы түзмөк кошуу үчүн чыкылдатыңыз"</string>
- <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея кубатынын деңгээли белгисиз."</string>
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батареянын деңгээли белгисиз."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string>
<string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> менен туташты."</string>
<string name="accessibility_not_connected" msgid="4061305616351042142">"Интернет жок."</string>
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Кошуу"</string>
<string name="manage_users" msgid="1823875311934643849">"Колдонуучуларды башкаруу"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Бул билдирмени бөлүнгөн экранда сүйрөөгө болбойт."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi жеткиликсиз"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Маанилүү сүйлөшүүлөр режими"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Ойготкуч коюлду"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Кулпу экранын тууралоо"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Кулпуланган экранды тууралоо үчүн кулпусун ачыңыз"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi жеткиликтүү эмес"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера бөгөттөлдү"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера менен микрофон бөгөттөлдү"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон бөгөттөлдү"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Сенсордук тактадагы жаңсоолор, ыкчам баскычтар жана башкалар жөнүндө билип алыңыз"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Артка кайтуу жаңсоосу"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Башкы бетке өтүү жаңсоосу"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Аракет баскычы"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Бүттү"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Артка кайтуу"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Кайтуу үчүн сенсордук тактанын каалаган жерин үч манжаңыз менен солго же оңго сүрүңүз.\n\nОшондой эле Action + ESC баскычтарынын айкалышын колдоно аласыз."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Каалаган убакта башкы экранга өтүү үчүн экранды үч манжаңыз менен ылдыйдан жогору карай сүрүңүз."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Сонун!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"\"Башкы бетке өтүү\" жаңсоосун үйрөндүңүз."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Аракет баскычы"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Бардык колдонмолоруңузду көрүү үчүн баскычтобуңуздагы аракет баскычын басыңыз"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Куттуктайбыз!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Үч манжаңыз менен өйдө сүрүп, кармап туруңуз. Башка жаңсоолорду үйрөнүү үчүн таптаңыз."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Бардык колдонмолорду көрүү үчүн баскычтобуңузду колдонуңуз"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Каалаганда аракет баскычын басыңыз. Башка жаңсоолорду үйрөнүү үчүн таптаңыз."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Кошумча караңгылатуу эми жарыктык тилкесинде жайгашкан"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Эми экраныңыздын өйдө жагынан жарыктыктын деңгээлин азайтып, экранды кошумча караңгылата аласыз.\n\nМуну караңгы жерде турганыңызда колдонуу сунушталат."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Кошумча караңгылатуу ыкчам баскычын өчүрүү"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Кошумча караңгылатуу ыкчам баскычы өчүрүлдү. Жарыктыкты азайтуу үчүн кадимки жарыктык тилкесин колдонуңуз."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Байланыш"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Атайын мүмкүнчүлүктөр"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Утилиталар"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Купуялык"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Колдонмолор сунуштады"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Экран"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгисиз"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index bc0c22d..67a11d4 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"ເພີ່ມ"</string>
<string name="manage_users" msgid="1823875311934643849">"ຈັດການຜູ້ໃຊ້"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ການແຈ້ງເຕືອນນີ້ບໍ່ຮອງຮັບການລາກເພື່ອແບ່ງໜ້າຈໍ"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ບໍ່ສາມາດໃຊ້ Wi‑Fi ໄດ້"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ໂໝດຄວາມສຳຄັນ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ຕັ້ງໂມງປຸກແລ້ວ"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ປັບແຕ່ງໜ້າຈໍລັອກ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ປົດລັອກເພື່ອປັບແຕ່ງໜ້າຈໍລັອກ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ບໍ່ພ້ອມໃຫ້ນຳໃຊ້"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ກ້ອງຖ່າຍຮູບຖືກບລັອກຢູ່"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ກ້ອງຖ່າຍຮູບ ແລະ ໄມໂຄຣໂຟນຖືກບລັອກຢູ່"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ໄມໂຄຣໂຟນຖືກບລັອກຢູ່"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ສຶກສາທ່າທາງຂອງແຜ່ນສຳຜັດ, ຄີລັດ ແລະ ອື່ນໆ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ທ່າທາງສຳລັບກັບຄືນ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ທ່າທາງສຳລັບໜ້າຫຼັກ"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ປຸ່ມຄຳສັ່ງ"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ແລ້ວໆ"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ກັບຄືນ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ເພື່ອກັບຄືນ, ໃຫ້ໃຊ້ 3 ນິ້ວປັດຊ້າຍ ຫຼື ຂວາບ່ອນໃດກໍໄດ້ເທິງແຜ່ນສຳຜັດ.\n\nທ່ານຍັງສາມາດໃຊ້ຄຳສັ່ງຄີລັດ + ESC ສຳລັບການດຳເນີນການນີ້ໄດ້ນຳ."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ເພື່ອໄປຫາໜ້າຫຼັກຂອງທ່ານຕອນໃດກໍໄດ້, ໃຫ້ປັດຂຶ້ນດ້ວຍສາມນິ້ວຈາກລຸ່ມສຸດຂອງໜ້າຈໍຂອງທ່ານ."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ດີຫຼາຍ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ທ່ານໃຊ້ທ່າທາງໄປໜ້າຫຼັກສຳເລັດແລ້ວ."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ປຸ່ມຄຳສັ່ງ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ເພື່ອເຂົ້າເຖິງແອັບ, ໃຫ້ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານ."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ຂໍສະແດງຄວາມຍິນດີ!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ໃຊ້ 3 ນິ້ວປັດຂຶ້ນ ແລ້ວຄ້າງໄວ້. ແຕະເພື່ອສຶກສາທ່າທາງເພີ່ມເຕີມ."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ໃຊ້ແປ້ນພິມຂອງທ່ານເພື່ອເບິ່ງແອັບທັງໝົດ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ກົດປຸ່ມຄຳສັ່ງໄດ້ທຸກເວລາ. ແຕະເພື່ອສຶກສາທ່າທາງເພີ່ມເຕີມ."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"ຕອນນີ້ການຫຼຸດແສງເປັນພິເສດເປັນສ່ວນໜຶ່ງຂອງແຖບຄວາມສະຫວ່າງແລ້ວ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ຕອນນີ້ທ່ານສາມາດເຮັດໃຫ້ໜ້າຈໍມືດລົງເປັນພິເສດໄດ້ໂດຍການຫຼຸດລະດັບຄວາມສະຫວ່າງລົງໃຫ້ຫຼາຍຂຶ້ນຈາກເທິງສຸດຂອງໜ້າຈໍຂອງທ່ານ.\n\nຄຸນສົມບັດນີ້ຈະເຮັດວຽກໄດ້ດີທີ່ສຸດເມື່ອທ່ານຢູ່ໃນສະພາບແວດລ້ອມທີ່ມືດ."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"ລຶບທາງລັດທີ່ຫຼຸດແສງເປັນພິເສດອອກ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"ລຶບທາງລັດທີ່ຫຼຸດແສງເປັນພິເສດອອກແລ້ວ. ເພື່ອຫຼຸດຄວາມສະຫວ່າງຂອງທ່ານລົງ, ໃຫ້ໃຊ້ແຖບຄວາມສະຫວ່າງປົກກະຕິ."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ການເຊື່ອມຕໍ່"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ການຊ່ວຍເຂົ້າເຖິງ"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ບໍລິການສາທາລະນູປະໂພກ"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"ຄວາມເປັນສ່ວນຕົວ"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ສະໜອງໃຫ້ໂດຍແອັບ"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ການສະແດງຜົນ"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ບໍ່ຮູ້ຈັກ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 91f8398..c813416 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Pridėti prie užrašo"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Įtraukti nuorodą"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Nuorodų negalima pridėti iš kitų profilių"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekrano vaizdo įrašytuvas"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Apdorojam. ekrano vaizdo įraš."</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Pridėti"</string>
<string name="manage_users" msgid="1823875311934643849">"Tvarkyti naudotojus"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Šio pranešimo vilkimas išskaidyto ekrano režimu nepalaikomas"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"„Wi‑Fi“ ryšys nepasiekiamas"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteto režimas"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signalas nustatytas"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Užrakinimo ekrano tinkinimas"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Atrakinę tinkinkite užrakinimo ekraną"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"„Wi-Fi“ ryšys nepasiekiamas"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Fotoaparatas užblokuotas"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparatas ir mikrofonas užblokuoti"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonas užblokuotas"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Sužinokite jutiklinės dalies gestus, sparčiuosius klavišus ir kt."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Grįžimo atgal gestas"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Pagrindinio ekrano gestas"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Veiksmų klavišas"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Atlikta"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Grįžti"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Jei norite grįžti, perbraukite kairėn arba dešinėn trimis pirštais bet kurioje jutiklinės dalies vietoje.\n\nTaip pat galite naudoti šį spartųjį klavišą: veiksmų klavišas + klavišas „Esc“."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Jei norite bet kada pasiekti pagrindinį ekraną, perbraukite aukštyn trim pirštais iš ekrano apačios."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Šaunu!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Atlikote perėjimo į pagrindinį ekraną gestą."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Veiksmų klavišas"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Jei norite pasiekti programas, paspauskite klaviatūros veiksmų klavišą."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Sveikiname!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Perbraukite aukštyn trimis pirštais ir palaikykite. Palieskite, kad sužinotumėte daugiau gestų."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Naudokite klaviatūrą, kad peržiūrėtumėte visas programas"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Bet kuriuo metu paspauskite veiksmų klavišą. Palieskite, kad sužinotumėte daugiau gestų."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Funkcija „Itin blanku“ dabar yra ryškumo juostos dalis"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Dabar galite padaryti ekraną itin blankų, dar labiau sumažindami ryškumo lygį nuo ekrano viršaus.\n\nŠi funkcija geriausiai veikia, kai esate tamsioje aplinkoje."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Pašalinti funkcijos „Itin blanku“ spartųjį klavišą"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Funkcijos „Itin blanku“ spartusis klavišas pašalintas. Jei norite sumažinti ryškumą, naudokite įprastą ryškumo juostą."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Ryšiai"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Pritaikomumas"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Paslaugų programos"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privatumas"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Teikia programos"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Ekranas"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nežinoma"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 29af399..a2e4130 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Pievienot piezīmei"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Iekļaut saiti"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Nevar pievienot saites no citiem profiliem."</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekrāna ierakstītājs"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Aktīvs paziņojums par ekrāna ierakstīšanas sesiju"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Pievienot"</string>
<string name="manage_users" msgid="1823875311934643849">"Pārvaldīt"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Šis paziņojums neatbalsta vilkšanu uz sadalīto ekrānu."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nav pieejams"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritātes režīms"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signāls ir iestatīts"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Pielāgot bloķēšanas ekrānu"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Bloķēšanas ekrāna pielāgošana pēc atbloķēšanas"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nav pieejams"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera ir bloķēta"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameras un mikrofona lietošana ir bloķēta"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofons ir bloķēts"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Uzziniet par skārienpaliktņa žestiem, īsinājumtaustiņiem un citām iespējām."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Žests pāriešanai atpakaļ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Žests pāriešanai uz sākumu"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Darbību taustiņš"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gatavs"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Atpakaļ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Lai atgrieztos, ar trīs pirkstiem velciet pa kreisi vai pa labi jebkurā vietā uz skārienpaliktņa.\n\nVarat arī izmantot šim nolūkam īsinājumtaustiņus: darbību taustiņu + Esc."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Lai jebkurā brīdī pārietu uz sākuma ekrānu, ar trim pirkstiem velciet augšup no ekrāna apakšdaļas."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Lieliski!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Jūs sekmīgi veicāt sākuma ekrāna atvēršanas žestu."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Darbību taustiņš"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Lai piekļūtu savām lietotnēm, tastatūrā nospiediet darbību taustiņu."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Apsveicam!"</string>
@@ -1434,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Ar trīs pirkstiem velciet augšup un turiet. Lai apgūtu citus žestus, pieskarieties šeit."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Visu lietotņu skatīšana, izmantojot tastatūru"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Jebkurā laikā varat nospiest darbību taustiņu. Lai apgūtu citus žestus, pieskarieties šeit."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Papildu aptumšošana tagad ir iekļauta spilgtuma joslā"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Tagad varat veikt ekrāna papildu aptumšošanu, vēl vairāk samazinot spilgtumu ekrāna augšdaļā.\n\nTas darbojas vislabāk, ja esat tumšā vietā."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Noņemt papildu aptumšošanas saīsni"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Papildu aptumšošanas saīsne ir noņemta. Lai samazinātu spilgtumu, izmantojiet parasto spilgtuma joslu."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 11fb67c..d4b066e 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Додај во белешка"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Опфати линк"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Не може да се додаваат линкови од други профили"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Снимач на екран"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Се обработува снимка од екран"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Тековно известување за сесија за снимање на екранот"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Додај"</string>
<string name="manage_users" msgid="1823875311934643849">"Управувајте со корисниците"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Известувањево не поддржува влечење на поделен екран"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi е недостапна"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетен режим"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Алармот е наместен"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Приспособете го заклучениот екран"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Отклучување за приспособување на заклучениот екран"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi не е достапно"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерата е блокирана"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камерата и микрофонот се блокирани"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофонот е блокиран"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Научете движења за допирната подлога, кратенки од тастатурата и друго"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Движење за назад"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Движење за почетен екран"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Копче за дејство"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"За да се вратите назад, повлечете налево или надесно со три прста каде било на допирната подлога.\n\nЗа ова може да ја користите и кратенката од тастатурата Action + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"За да одите на вашиот почетен екран кога сакате, повлечете нагоре со три прсти од дното на екранот."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Одлично!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Го научивте движењето за враќање на почетниот екран."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Копче за дејство"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"За да пристапите до апликациите, притиснете го копчето за дејство на тастатурата."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Честитки!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Повлечете нагоре и задржете со три прста. Допрете за да научите повеќе движења."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Користете ја тастатурата за да ги видите сите апликации"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Притиснете го копчето за дејство кога сакате. Допрете за да научите повеќе движења."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Отсега „Дополнително затемнување“ е дел од лентата за осветленост"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Отсега може да го затемнувате екранот дополнително со намалување на нивото на осветленост од горниот дел на екранот.\n\nОва функционира најдобро кога сте во темна средина."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Отстрани ја кратенката за „Дополнително затемнување“"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Кратенката за „Дополнително затемнување“ е отстранета. Користете ја стандардната лента за осветленост за да ја намалите осветленоста."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Поврзливост"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Пристапност"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Услужни програми"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Приватност"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Обезбедено од апликации"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Екран"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Непознато"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 720275e..fbb36b1 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"ചേർക്കുക"</string>
<string name="manage_users" msgid="1823875311934643849">"ഉപയോക്താക്കളെ മാനേജ് ചെയ്യുക"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"സ്പ്ലിറ്റ് സ്ക്രീനിലേക്ക് വലിച്ചിടുന്നതിനെ ഈ അറിയിപ്പ് പിന്തുണയ്ക്കുന്നില്ല"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"വൈഫൈ ലഭ്യമല്ല"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"മുൻഗണനാ മോഡ്"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"അലാറം സജ്ജീകരിച്ചു"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ലോക്ക് സ്ക്രീൻ ഇഷ്ടാനുസൃതമാക്കൂ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ലോക്ക് സ്ക്രീൻ ഇഷ്ടാനുസൃതമാക്കാൻ അൺലോക്ക് ചെയ്യുക"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"വൈഫൈ ലഭ്യമല്ല"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ക്യാമറ ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ക്യാമറയും മൈക്രോഫോണും ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"മൈക്രോഫോൺ ബ്ലോക്ക് ചെയ്തിരിക്കുന്നു"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ടച്ച്പാഡ് ജെസ്ച്ചറുകൾ, കീബോർഡ് കുറുക്കുവഴികൾ എന്നിവയും മറ്റും മനസ്സിലാക്കുക"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"\'മടങ്ങുക\' ജെസ്ച്ചർ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ഹോം ജെസ്ച്ചർ"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ആക്ഷൻ കീ"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"പൂർത്തിയായി"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"മടങ്ങുക"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"തിരികെ പോകാൻ, ടച്ച്പാഡിൽ എവിടെയെങ്കിലും മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് ഇടത്തേക്കോ വലത്തേക്കോ സ്വൈപ്പ് ചെയ്യുക.\n\nഇതിന് Action + ESC കീബോഡ് കുറുക്കുവഴികളും നിങ്ങൾക്ക് ഉപയോഗിക്കാം."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ഏതുസമയത്തും ഹോം സ്ക്രീനിലേക്ക് പോകാൻ, മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യൂ."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"കൊള്ളാം!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Action കീ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"നിങ്ങളുടെ ആപ്പുകൾ ആക്സസ് ചെയ്യാൻ, നിങ്ങളുടെ കീബോർഡിലെ Action കീ അമർത്തുക."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"അഭിനന്ദനങ്ങൾ!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"മൂന്ന് വിരലുകൾ കൊണ്ട് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിക്കുക. കൂടുതൽ ജെസ്ച്ചറുകളറിയാൻ ടാപ്പ് ചെയ്യൂ."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"എല്ലാ ആപ്പുകളും കാണാൻ നിങ്ങളുടെ കീബോർഡ് ഉപയോഗിക്കുക"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ഏതുസമയത്തും ആക്ഷൻ കീ അമർത്തുക. കൂടുതൽ ജെസ്ച്ചറുകൾ മനസ്സിലാക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"കൂടുതൽ ഡിം ചെയ്യൽ, ഇപ്പോൾ തെളിച്ചം ബാറിന്റെ ഭാഗമാണ്"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"മുകളിൽ നിന്ന് തെളിച്ചം കുറയ്ക്കുന്നതിലൂടെ നിങ്ങൾക്ക് ഇപ്പോൾ സ്ക്രീൻ കൂടുതൽ മങ്ങിക്കാൻ കഴിയും.\n\nനിങ്ങൾ ഇരുണ്ട മുറിയിലായിരിക്കുമ്പോൾ ഇത് മികച്ച രീതിയിൽ പ്രവർത്തിക്കുന്നു."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"കൂടുതൽ ഡിം ചെയ്യൽ കുറുക്കുവഴി നീക്കം ചെയ്യുക"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"കൂടുതൽ ഡിം ചെയ്യാനുള്ള കുറുക്കുവഴി നീക്കം ചെയ്തു. തെളിച്ചം കുറയ്ക്കാൻ, സാധാരണ \'തെളിച്ചം ബാർ\' ഉപയോഗിക്കുക."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"കണക്റ്റിവിറ്റി"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ഉപയോഗസഹായി"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"യൂട്ടിലിറ്റികൾ"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"സ്വകാര്യത"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ആപ്പുകൾ നൽകുന്നത്"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ഡിസ്പ്ലേ"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"അജ്ഞാതം"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 50a942e..57948a27 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Тэмдэглэлд нэмэх"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Холбоосыг оруулах"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Бусад профайлаас холбоос нэмэх боломжгүй"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Дэлгэцийн үйлдэл бичигч"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Нэмэх"</string>
<string name="manage_users" msgid="1823875311934643849">"Хэрэглэгчдийг удирдах"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Энэ мэдэгдэл нь дэлгэцийг хуваах горим руу чирэхийг дэмждэггүй"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi боломжгүй"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Чухал горим"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Сэрүүлгийг тохируулсан"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Түгжээтэй дэлгэцийг өөрчлөх"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Түгжээтэй дэлгэцийг өөрчлөхийн тулд түгжээг тайлна уу"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi боломжгүй байна"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерыг блоклосон"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камер болон микрофоныг блоклосон"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофоныг блоклосон"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Мэдрэгч самбарын зангаа, товчлуурын шууд холбоос болон бусад зүйлийг мэдэж аваарай"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Буцах зангаа"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Үндсэн нүүрний зангаа"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Тусгай товчлуур"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Болсон"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Буцах"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Буцахын тулд мэдрэгч самбар дээр гурван хуруугаар хүссэн газраа зүүн эсвэл баруун тийш шударна уу.\n\nТа мөн үүнийг хийхэд Action + ESC товчлуурын шууд холбоосыг ашиглах боломжтой."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Үндсэн нүүр лүүгээ хүссэн үедээ очихын тулд дэлгэцийнхээ доод талаас гурван хуруугаараа дээш шударна уу."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Янзтай!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Та үндсэн нүүр лүү очих зангааг гүйцэтгэлээ."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Тусгай товчлуур"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Аппууддаа хандахын тулд гар дээр тань байх тусгай товчлуурыг дарна уу."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Баяр хүргэе!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Гурван хуруугаа ашиглан дээш шудраад, удаан дарна уу. Илүү олон зангаа сурахын тулд товшино уу."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Бүх аппыг харахын тулд гараа ашиглах"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Тусгай товчлуурыг хүссэн үедээ дарна уу. Илүү олон зангаа сурахын тулд товшино уу."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Хэт бүүдгэр онцлог одоо гэрэлтүүлгийн самбарын нэг хэсэг боллоо"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Та одоо дэлгэцийнхээ дээд талаас гэрэлтүүлгийн түвшнийг бүр илүү багасгаснаар дэлгэцийг хэт бүүдгэр болгох боломжтой.\n\nЭнэ нь таныг харанхуй орчинд байхад хамгийн сайн ажилладаг."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Хэт бүүдгэр онцлогийн товчлолыг хасах"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Хэт бүүдгэр онцлогийн товчлолыг хассан. Гэрэлтүүлгээ багасгахын тулд энгийн гэрэлтүүлгийн самбарыг ашиглана уу."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Холболт"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Хандалт"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Хэрэгсэл"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Нууцлал"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Аппуудаас өгсөн"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Дэлгэц"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Тодорхойгүй"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 75ef6e0..0f3b051 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"जोडा"</string>
<string name="manage_users" msgid="1823875311934643849">"वापरकर्ते व्यवस्थापित करा"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ही सूचना स्प्लिट स्क्रीनवर ड्रॅग करण्याला सपोर्ट करत नाही"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"वाय-फाय उपलब्ध नाही"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राधान्य मोड"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट केला"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"कस्टमाइझ लॉक स्क्रीन"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"लॉक स्क्रीन कस्टमाइझ करण्यासाठी अनलॉक करा"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"वाय-फाय उपलब्ध नाही"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"कॅमेरा ब्लॉक केला"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"कॅमेरा आणि मायक्रोफोन ब्लॉक केले आहेत"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"मायक्रोफोन ब्लॉक केला"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचपॅड जेश्चर, कीबोर्ड शॉर्टकट आणि आणखी बरेच काही जाणून घ्या"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"मागे जा जेश्चर"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम जेश्चर"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"अॅक्शन की"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"पूर्ण झाले"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"मागे जा"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"मागे जाण्यासाठी, तीन बोटांनी टचपॅडवर कुठेही डावीकडे किंवा उजवीकडे स्वाइप करा.\n\nतुम्ही यासाठी Action + ESC हा कीबोर्ड शॉर्टकटदेखील वापरू शकता."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"कधीही तुमच्या होम स्क्रीनवर जाण्यासाठी, तीन बोटांनी तुमच्या स्क्रीनच्या तळापासून स्वाइप करा."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"छान!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"तुम्ही गो होम जेश्चर पूर्ण केले आहे."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"अॅक्शन की"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"तुमची ॲप्स अॅक्सेस करण्यासाठी, तुमच्या कीबोर्डवरील अॅक्शन की प्रेस करा."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"अभिनंदन!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"तीन बोटांनी वरती आणि खाली स्वाइप करा. आणखी जेश्चर जाणून घेण्यासाठी टॅप करा."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"सर्व ॲप्स पाहण्यासाठी तुमचा कीबोर्ड वापरा"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"अॅक्शन की कधीही प्रेस करा. आणखी जेश्चर जाणून घेण्यासाठी टॅप करा."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"आणखी डिम हे आता ब्राइटनेस बारचा भाग आहे"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"तुम्ही आता तुमच्या स्क्रीनच्या सर्वात वरून ब्राइटनेसची पातळी आणखी कमी करून स्क्रीनला आणखी डिम करू शकता.\n\nतुम्ही गडद वातावरणात असता, तेव्हा हे सर्वोत्तम कार्य करते."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"आणखी डिमचा शॉर्टकट काढून टाका"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"आणखी डिमचा शॉर्टकट काढून टाकला आहे. तुमचा ब्राइटनेस कमी करण्यासाठी, नेहमीचा ब्राइटनेस बार वापरा."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"कनेक्टिव्हिटी"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"अॅक्सेसिबिलिटी"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"उपयुक्तता"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"गोपनीयता"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"अॅप्सद्वारे पुरवलेले"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"डिस्प्ले"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"अज्ञात"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index e8213ba..38434c5 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Tambah"</string>
<string name="manage_users" msgid="1823875311934643849">"Urus pengguna"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Pemberitahuan ini tidak menyokong penyeretan kepada skrin pisah"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi dimatikan"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Mod keutamaan"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Penggera ditetapkan"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Sesuaikan skrin kunci"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Buka kunci untuk menyesuaikan skrin kunci"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi tidak tersedia"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera disekat"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dan mikrofon disekat"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon disekat"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Ketahui gerak isyarat pad sentuh, pintasan papan kekunci dan pelbagai lagi"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gerak isyarat kembali"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gerak isyarat pergi ke laman utama"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Kekunci tindakan"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Selesai"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kembali"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Untuk kembali, leret ke kiri atau ke kanan menggunakan tiga jari di mana-mana sahaja pada pad sentuh.\n\nAnda juga boleh menggunakan pintasan papan kekunci Action + ESC untuk kembali."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Untuk mengakses skrin utama anda pada bila-bila masa, leret ke atas menggunakan tiga jari daripada bahagian bawah skrin anda."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bagus!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Anda telah melengkapkan gerak isyarat akses laman utama."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Kekunci tindakan"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Untuk mengakses semua apl anda, tekan kekunci tindakan pada papan kekunci anda."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tahniah!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Leret ke atas, tahan dengan tiga jari. Ketik untuk mengetahui lebih lanjut tentang gerak isyarat."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gunakan papan kekunci anda untuk melihat semua apl"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tekan kekunci tindakan pada bila-bila masa. Ketik dan ketahui lebih lanjut tentang gerak isyarat."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Kini ciri amat malap merupakan sebahagian daripada bar kecerahan"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Kini anda boleh menjadikan skrin amat malap dengan merendahkan tahap kecerahan lebih jauh daripada bahagian atas skrin anda.\n\nCiri ini berfungsi paling baik apabila anda berada dalam persekitaran yang gelap."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Alih keluar pintasan amat malap"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Pintasan amat malap dialih keluar. Untuk mengurangkan kecerahan anda, gunakan bar kecerahan biasa."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Kesambungan"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Kebolehaksesan"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utiliti"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privasi"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Disediakan oleh apl"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Paparan"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tidak diketahui"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 8abb63d..ef4b04d 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"ထည့်ရန်"</string>
<string name="manage_users" msgid="1823875311934643849">"အသုံးပြုသူများ စီမံရန်"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ဤအကြောင်းကြားချက်သည် ‘မျက်နှာပြင် ခွဲ၍ပြသခြင်း’ သို့ ဖိဆွဲမှုကို မပံ့ပိုးပါ"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi မရပါ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ဦးစားပေးမုဒ်"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"နိုးစက် သတ်မှတ်ထားသည်"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"လော့ခ်မျက်နှာပြင်စိတ်ကြိုက်လုပ်ရန်"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"လော့ခ်မျက်နှာပြင် စိတ်ကြိုက်လုပ်ရန် ဖွင့်ပါ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi မရနိုင်ပါ"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ကင်မရာကို ပိတ်ထားသည်"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ကင်မရာနှင့် မိုက်ခရိုဖုန်းကို ပိတ်ထားသည်"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"မိုက်ခရိုဖုန်းကို ပိတ်ထားသည်"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"တာ့ချ်ပက်လက်ဟန်များ၊ လက်ကွက်ဖြတ်လမ်းများ စသည်တို့ကို လေ့လာပါ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"နောက်သို့ လက်ဟန်"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ပင်မစာမျက်နှာ လက်ဟန်"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"လုပ်ဆောင်ချက်ကီး"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ပြီးပြီ"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ပြန်သွားရန်"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"နောက်ပြန်သွားရန် တာ့ချ်ပက်ပေါ်ရှိ မည်သည့်နေရာ၌မဆို လက်သုံးချောင်းဖြင့် ဘယ် (သို့) ညာသို့ ပွတ်ဆွဲပါ။\n\n၎င်းအတွက် လက်ကွက်ဖြတ်လမ်း Action + ESC ကိုလည်း သုံးနိုင်သည်။"</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ပင်မစာမျက်နှာသို့ အချိန်မရွေးသွားရန် စခရင်အောက်ခြေမှ အပေါ်သို့ လက်သုံးချောင်းဖြင့် ပွတ်ဆွဲပါ။"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ကောင်းသည်။"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ပင်မစာမျက်နှာသို့သွားသည့် လက်ဟန် အပြီးသတ်လိုက်ပါပြီ။"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"လုပ်ဆောင်ချက်ကီး"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"သင့်အက်ပ်များသုံးရန် ကီးဘုတ်ပေါ်ရှိ လုပ်ဆောင်ချက်ကီးကို နှိပ်ပါ။"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ဂုဏ်ယူပါသည်။"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"လက်သုံးချောင်းဖြင့် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ။ လက်ဟန်များ ပိုမိုလေ့လာရန် တို့ပါ။"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"အက်ပ်အားလုံးကြည့်ရန် သင့်ကီးဘုတ်ကို သုံးပါ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"လုပ်ဆောင်ချက်ကီးကို အချိန်မရွေးနှိပ်ပါ။ လက်ဟန်များ ပိုမိုလေ့လာရန် တို့ပါ။"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"ပိုမှိန်ခြင်းသည် တောက်ပမှုဘားတွင် ပါဝင်လာပြီ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"သင့်စခရင်ထိပ်ဆုံး၌ပင် တောက်ပမှုအဆင့်လျှော့ချခြင်းဖြင့် စခရင်ကို ပိုမှိန်အောင် လုပ်နိုင်ပါပြီ။\n\nသင်သည် မှောင်သောပတ်ဝန်းကျင်၌ရှိချိန် ၎င်းက အကောင်းဆုံးအလုပ်လုပ်သည်။"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"ပိုမှိန်ခြင်း ဖြတ်လမ်း ဖယ်ရှားရန်"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"ပိုမှိန်ခြင်း ဖြတ်လမ်းကို ဖယ်ရှားလိုက်ပြီ။ တောက်ပမှုလျှော့ရန် ပုံမှန် တောက်ပမှုဘားကို အသုံးပြုပါ။"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ချိတ်ဆက်နိုင်မှု"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"အများသုံးနိုင်မှု"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"အထောက်အကူပြု ဆော့ဖ်ဝဲလ်များ"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"ကိုယ်ရေးအချက်အလက် လုံခြုံမှု"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"အက်ပ်များက ပံ့ပိုးထားသည်"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ဖန်သားပြင်"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"အမျိုးအမည်မသိ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 8ccb776..55535dd 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Legg til i notat"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Inkluder linken"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Linker kan ikke legges til fra andre profiler"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skjermopptak"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Vedvarende varsel for et skjermopptak"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Legg til"</string>
<string name="manage_users" msgid="1823875311934643849">"Brukervalg"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Dette varselet støtter ikke at du drar det til en delt skjerm"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi er utilgjengelig"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteringsmodus"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmen er stilt inn"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Tilpass låseskjermen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Du må låse opp enheten for å tilpasse låseskjermen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi er ikke tilgjengelig"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameraet er blokkert"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameraet og mikrofonen er blokkert"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen er blokkert"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Lær deg styreflatebevegelser, hurtigtaster med mer"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tilbakebevegelse"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Startskjermbevegelse"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Handlingstast"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Ferdig"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Gå tilbake"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"For å gå tilbake, sveip mot høyre eller venstre med tre fingre hvor som helst på styreflaten.\n\nDu kan også gjøre dette med hurtigtasten Action + Esc."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"For å gå til startskjermen, sveip opp med tre fingre fra bunnen av skjermen når som helst."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bra!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du har fullført bevegelsen for å gå til startskjermen."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Handlingstast"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"For å åpne appene dine, trykk på handlingstasten på tastaturet."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulerer!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Sveip opp og hold med tre fingre. Trykk for å lære flere bevegelser."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Bruk tastaturet for å se alle apper"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Trykk på handlingstasten når som helst. Trykk for å lære flere bevegelser."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Nå er ekstra dimmet en del av lysstyrkeraden"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Nå kan du gjøre skjermen ekstra dimmet ved å redusere lysstyrkenivået enda mer fra toppen av skjermen.\n\nDette fungerer best i mørke omgivelser."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Fjern hurtigtasten for ekstra dimmet"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Hurtigtasten for ekstra dimmet er fjernet. For å redusere lysstyrken kan du bruke den vanlige lysstyrkeraden."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Tilkobling"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Tilgjengelighet"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Systemverktøy"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Personvern"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Levert av apper"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Skjerm"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ukjent"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 60e99ea..68cca07 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"हाल्नुहोस्"</string>
<string name="manage_users" msgid="1823875311934643849">"प्रयोगकर्ताहरूको व्यवस्थापन गर्नुहोस्"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"यो सूचना ड्र्याग गरेर स्प्लिट स्क्रिनमा लैजान मिल्दैन"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi उपलब्ध छैन"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"प्राथमिकता मोड"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"अलार्म सेट गरिएको छ"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"लक स्क्रिन कस्टमाइज गर्नुहोस्"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"लक स्क्रिन कस्टमाइज गर्न अनलक गर्नुहोस्"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi उपलब्ध छैन"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"क्यामेरा ब्लक गरिएको छ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"क्यामेरा र माइक्रोफोन ब्लक गरिएको छ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"माइक्रोफोन ब्लक गरिएको छ"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"टचप्याड जेस्चर, किबोर्डका सर्टकट र अन्य कुरा प्रयोग गर्न सिक्नुहोस्"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ब्याक जेस्चर"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"होम जेस्चर"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"एक्सन की"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"सम्पन्न भयो"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"पछाडि जानुहोस्"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"पछाडि जान तीन वटा औँलाले टचप्याडमा कतै छोएर बायाँ वा दायाँतिर स्वाइप गर्नुहोस्।\n\nतपाईं यसका लागि किबोर्डको सर्टकट \"Action + ESC\" पनि प्रयोग गर्न सक्नुहुन्छ।"</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"जुनसुकै बेला आफ्नो होम स्क्रिनमा जान स्क्रिनको फेदबाट तीन वटा औँलाले माथितिर स्वाइप गर्नुहोस्।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"राम्रो!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"तपाईंले \"होम स्क्रिनमा जानुहोस्\" नामक जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो।"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"एक्सन की"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"आफ्ना एपहरू एक्सेस गर्न आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्।"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"बधाई छ!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"तिन वटा औँला प्रयोग गरी माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्। थप जेस्चर प्रयोग गर्ने तरिका सिक्न ट्याप गर्नुहोस्।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"सबै एपहरू हेर्न आफ्नो किबोर्ड प्रयोग गर्नुहोस्"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"जुनसुकै बेला एक्सन की थिच्नुहोस्। थप जेस्चर प्रयोग गर्ने तरिका सिक्न ट्याप गर्नुहोस्।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"\"अझै मधुरो\" सुविधा अब ब्राइटनेस बारमा समावेश गरिएको छ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"तपाईं अब आफ्नो स्क्रिनको सिरानबाट चमकको स्तर घटाएर आफ्नो स्क्रिन अझै मधुरो बनाउन सक्नुहुन्छ।\n\nतपाईं अँध्यारो ठाउँमा भएका बेला यो सुविधाले अझ राम्रोसँग काम गर्छ।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"\"अझै मधुरो\" सर्टकट हटाउनुहोस्"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"\"अझै मधुरो\" सर्टकट हटाइएको छ। स्क्रिनको चमक घटाउन \"रेगुलर ब्राइटनेस बार\" प्रयोग गर्नुहोस्।"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"कनेक्टिभिटी"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"सर्वसुलभता"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"युटिलिटी"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"गोपनीयता"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"एपले उपलब्ध गराएका"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"डिस्प्ले"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"अज्ञात"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 4b43ab1..2e9fc8e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Toevoegen"</string>
<string name="manage_users" msgid="1823875311934643849">"Gebruikers beheren"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Deze melding biedt geen ondersteuning voor slepen naar het gesplitste scherm"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi niet beschikbaar"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioriteitsmodus"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Wekker gezet"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Vergrendelscherm aanpassen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ontgrendelen om het vergrendelscherm aan te passen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi niet beschikbaar"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera geblokkeerd"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera en microfoon geblokkeerd"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfoon geblokkeerd"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Leer meer over onder andere touchpadgebaren en sneltoetsen"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gebaar voor terug"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gebaar voor startscherm"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Actietoets"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klaar"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Terug"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Als je wilt teruggaan, swipe je met 3 vingers naar links of rechts op de touchpad.\n\nJe kunt hiervoor ook de sneltoets Actie + ESC gebruiken."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Swipe met 3 vingers omhoog vanaf de onderkant van het scherm om naar het startscherm te gaan."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Mooi zo!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Je weet nu hoe je het gebaar Naar startscherm maakt."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Actietoets"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Als je toegang tot je apps wilt krijgen, druk je op de actietoets op je toetsenbord."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gefeliciteerd!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Swipe met 3 vingers omhoog en houd vast. Tik voor meer gebaren."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Je toetsenbord gebruiken om alle apps te bekijken"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Druk op de actietoets wanneer je wilt. Tik voor meer gebaren."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Extra dimmen maakt nu deel uit van de helderheidsbalk"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Je kunt het scherm nu extra dimmen door het helderheidsniveau nog verder te verlagen vanaf de bovenkant van het scherm.\n\nDit werkt het beste als je in een donkere omgeving bent."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Snelkoppeling voor extra dimmen verwijderen"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Snelkoppeling voor extra dimmen verwijderd. Als je de helderheid wilt verlagen, gebruik je de gewone helderheidsbalk."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Connectiviteit"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Toegankelijkheid"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Hulpprogramma\'s"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacy"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Geleverd door apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Scherm"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Onbekend"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index af4ee77..7eced26 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"ନୋଟରେ ଯୋଗ କରନ୍ତୁ"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"ଲିଙ୍କକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରନ୍ତୁ"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"ଅନ୍ୟ ପ୍ରୋଫାଇଲରୁ ଲିଙ୍କଗୁଡ଼ିକ ଯୋଗ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"ସ୍କ୍ରିନ ରେକର୍ଡର"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ଏକ ସ୍କ୍ରିନ୍ ରେକର୍ଡ୍ ସେସନ୍ ପାଇଁ ଚାଲୁଥିବା ବିଜ୍ଞପ୍ତି"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"ଯୋଗ କରନ୍ତୁ"</string>
<string name="manage_users" msgid="1823875311934643849">"ୟୁଜରମାନଙ୍କୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ଏହି ବିଜ୍ଞପ୍ତି ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ଟାଣିବାକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ପ୍ରାଥମିକତା ମୋଡ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ଆଲାରାମ ସେଟ"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ଲକ ସ୍କ୍ରିନକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ଲକ ସ୍କ୍ରିନକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ ଅନଲକ କରନ୍ତୁ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ୱାଇ-ଫାଇ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"କେମେରାକୁ ବ୍ଲକ କରାଯାଇଛି"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"କେମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ବ୍ଲକ କରାଯାଇଛି"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ମାଇକ୍ରୋଫୋନକୁ ବ୍ଲକ କରାଯାଇଛି"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ଟଚପେଡ ଜେଶ୍ଚର, କୀବୋର୍ଡ ସର୍ଟକଟ ଏବଂ ଆହୁରି ଅନେକ କିଛି ବିଷୟରେ ଜାଣନ୍ତୁ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ବେକ ଜେଶ୍ଚର"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ହୋମ ଜେଶ୍ଚର"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ଆକ୍ସନ କୀ"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ହୋଇଗଲା"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ପଛକୁ ଫେରନ୍ତୁ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ପଛକୁ ଫେରିବା ପାଇଁ ଯେ କୌଣସି ସ୍ଥାନରେ ତିନି ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରି ବାମ କିମ୍ବା ଡାହାଣକୁ ସ୍ୱାଇପ କରନ୍ତୁ।\n\nଏଥିପାଇଁ ଆପଣ କୀବୋର୍ଡ ସର୍ଟକଟ ଆକ୍ସନ + ESC ମଧ୍ୟ ବ୍ୟବହାର କରିପାରିବେ।"</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ଯେ କୌଣସି ସମୟରେ ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନକୁ ଯିବା ପାଇଁ ଆପଣଙ୍କ ସ୍କିନର ତଳୁ ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ବଢ଼ିଆ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ଆପଣ \'ହୋମକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ଆକ୍ସନ କୀ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ଆପଣଙ୍କ ଆପ୍ସ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣଙ୍କର କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ।"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ଅଭିନନ୍ଦନ!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ। ଜେଶ୍ଚରଗୁଡ଼ିକ ବିଷୟରେ ଅଧିକ ଜାଣିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ସମସ୍ତ ଆପ୍ସ ଭ୍ୟୁ କରିବା ପାଇଁ ଆପଣଙ୍କ କୀବୋର୍ଡକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ଯେ କୌଣସି ସମୟରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ। ଜେଶ୍ଚରଗୁଡ଼ିକ ବିଷୟରେ ଅଧିକ ଜାଣିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"ଅତିରିକ୍ତ ଡିମ ବର୍ତ୍ତମାନ ଉଜ୍ଜ୍ୱଳତା ବାରର ଅଂଶ ଅଟେ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ବର୍ତ୍ତମାନ ଆପଣ ଆପଣଙ୍କ ସ୍କ୍ରିନର ଶୀର୍ଷରୁ ଉଜ୍ଜ୍ୱଳତାର ଲେଭେଲ ହ୍ରାସ କରି ସ୍କ୍ରିନକୁ ଅତିରିକ୍ତ ଡିମ କରିପାରିବେ।\n\nଆପଣ ଏକ ଡାର୍କ ପରିବେଶରେ ଥିଲେ ଏହା ସବୁଠାରୁ ଭଲ କାମ କରେ।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"ଅତିରିକ୍ତ ଡିମ ସର୍ଟକଟକୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"ଅତିରିକ୍ତ ଡିମର ସର୍ଟକଟ କାଢ଼ି ଦିଆଯାଇଛି। ଆପଣଙ୍କ ଉଜ୍ଜ୍ୱଳତା ହ୍ରାସ କରିବା ପାଇଁ ନିୟମିତ ଉଜ୍ଜ୍ୱଳତା ବାର ବ୍ୟବହାର କରନ୍ତୁ।"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"କନେକ୍ଟିଭିଟି"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ଆକ୍ସେସିବିଲିଟୀ"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ୟୁଟିଲିଟି"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"ଗୋପନୀୟତା"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ଆପ୍ସ ଦ୍ୱାରା ପ୍ରଦାନ କରାଯାଇଛି"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ଡିସପ୍ଲେ"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ଅଜଣା"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index e6b275a..6a46613 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"ਨੋਟ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"ਲਿੰਕ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"ਹੋਰ ਪ੍ਰੋਫਾਈਲਾਂ ਤੋਂ ਲਿੰਕਾਂ ਨੂੰ ਸ਼ਾਮਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="manage_users" msgid="1823875311934643849">"ਵਰਤੋਂਕਾਰਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ਇਹ ਸੂਚਨਾ ਸਪਲਿਟ ਸਕ੍ਰੀਨ \'ਤੇ ਘਸੀਟਣ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ ਹੈ"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ਤਰਜੀਹੀ ਮੋਡ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ਅਲਾਰਮ ਸੈੱਟ ਹੈ"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ਲਾਕ ਸਕ੍ਰੀਨ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ਲਾਕ ਸਕ੍ਰੀਨ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"ਵਾਈ-ਫਾਈ ਉਪਲਬਧ ਨਹੀਂ"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"ਕੈਮਰਾ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"ਕੈਮਰਾ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤੇ ਗਏ"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਬਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ਟੱਚਪੈਡ ਇਸ਼ਾਰੇ, ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ ਬਾਰੇ ਜਾਣੋ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ਪਿੱਛੇ ਜਾਣ ਦਾ ਇਸ਼ਾਰਾ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ਹੋਮ \'ਤੇ ਜਾਣ ਦਾ ਇਸ਼ਾਰਾ"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ਕਾਰਵਾਈ ਕੁੰਜੀ"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ਹੋ ਗਿਆ"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ਵਾਪਸ ਜਾਓ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ਵਾਪਸ ਜਾਣ ਲਈ, ਟੱਚਪੈਡ \'ਤੇ ਕਿਤੇ ਵੀ ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਖੱਬੇ ਜਾਂ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ।\n\nਤੁਸੀਂ ਇਸ ਲਈ ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ Action + ESC ਦੀ ਵਰਤੋਂ ਵੀ ਕਰ ਸਕਦੇ ਹੋ।"</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਜਾਣ ਲਈ, ਤਿੰਨ ਉਂਗਲਾਂ ਨਾਲ ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ।"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ਵਧੀਆ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ਕਾਰਵਾਈ ਕੁੰਜੀ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ਆਪਣੀਆਂ ਐਪਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ, ਆਪਣੇ ਕੀ-ਬੋਰਡ \'ਤੇ ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ।"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ਵਧਾਈਆਂ!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ਤਿੰਨ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰ ਕੇ ਦਬਾਈ ਰੱਖੋ। ਹੋਰ ਇਸ਼ਾਰਿਆਂ ਨੂੰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ਸਾਰੀਆਂ ਐਪਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਵਰਤੋ"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ਕਿਸੇ ਵੀ ਸਮੇਂ ਕਾਰਵਾਈ ਕੁੰਜੀ ਦਬਾਓ। ਹੋਰ ਇਸ਼ਾਰਿਆਂ ਨੂੰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"\'ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ\' ਹੁਣ ਚਮਕ ਪੱਟੀ ਦਾ ਹਿੱਸਾ ਹੈ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ਤੁਸੀਂ ਹੁਣ ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਸਿਖਰ ਤੋਂ ਚਕਮ ਦੇ ਪੱਧਰ ਨੂੰ ਹੋਰ ਵੀ ਘੱਟ ਕਰ ਕੇ ਸਕ੍ਰੀਨ ਦੀ ਚਮਕ ਨੂੰ ਜ਼ਿਆਦਾ ਘੱਟ ਕਰ ਸਕਦੇ ਹੋ।\n\nਇਹ ਉਦੋਂ ਬਿਹਤਰੀਨ ਕੰਮ ਕਰਦੀ ਹੈ, ਜਦੋਂ ਤੁਸੀਂ ਹਨੇਰੇ ਵਿੱਚ ਹੁੰਦੇ ਹੋ।"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"\'ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ\' ਸ਼ਾਰਟਕੱਟ ਹਟਾਓ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"\'ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ\' ਸ਼ਾਰਟਕੱਟ ਹਟਾਇਆ ਗਿਆ। ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੀ ਚਕਮ ਨੂੰ ਘੱਟ ਕਰਨ ਲਈ, ਨਿਯਮਿਤ ਚਮਕ ਪੱਟੀ ਦੀ ਵਰਤੋਂ ਕਰੋ।"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"ਕਨੈਕਟੀਵਿਟੀ"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ਪਹੁੰਚਯੋਗਤਾ"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ਉਪਯੋਗਤਾਵਾਂ"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"ਪਰਦੇਦਾਰੀ"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ਐਪਾਂ ਵੱਲੋਂ ਮੁਹੱਈਆ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ਡਿਸਪਲੇ"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ਅਗਿਆਤ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 0fefcae..770d995 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj do notatek"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Dołącz link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Nie można dodawać linków z innych profili"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Nagrywanie ekranu"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Zarządzaj użytkownikami"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"To powiadomienie nie obsługuje dzielenia ekranu przez przeciąganie."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Sieć Wi‑Fi niedostępna"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Tryb priorytetowy"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm ustawiony"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Dostosuj ekran blokady"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Odblokuj, aby dostosować ekran blokady"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Sieć Wi-Fi jest niedostępna"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera jest zablokowana"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera i mikrofon są zablokowane"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon jest zablokowany"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Poznaj gesty na touchpada, skróty klawiszowe i inne funkcje"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gest przejścia wstecz"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gest przejścia na ekran główny"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Klawisz działania"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gotowe"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Wróć"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Aby przejść wstecz, przesuń 3 palcami w lewo lub w prawo w dowolnym miejscu touchpada.\n\nMożesz też użyć do tego skrótu klawiszowego Action + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Aby w dowolnym momencie wyświetlić ekran główny, przesuń od dołu ekranu w górę 3 palcami."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Super!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Gest przechodzenia na ekran główny został opanowany."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Klawisz działania"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Aby uzyskać dostęp do aplikacji, naciśnij klawisz działania na klawiaturze."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Gratulacje!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Przesuń w górę za pomocą 3 palców i przytrzymaj. Kliknij, aby poznać więcej gestów."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Wyświetlanie wszystkich aplikacji za pomocą klawiatury"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Naciśnij klawisz działania w dowolnym momencie. Kliknij, aby poznać więcej gestów."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Dodatkowe przyciemnienie jest teraz częścią paska jasności"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Możesz teraz dodatkowo przyciemnić ekran, jeszcze bardziej zmniejszając poziom jasności u góry ekranu.\n\nTa funkcja sprawdza się najlepiej, gdy jesteś w ciemnym otoczeniu."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Usuń skrót do dodatkowego przyciemnienia"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Skrót do dodatkowego przyciemnienia został usunięty. Aby zmniejszyć jasność, użyj standardowego paska jasności."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Łączność"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Ułatwienia dostępu"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Narzędzia"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Prywatność"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Z aplikacji"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Wyświetlacz"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nieznane"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 1331ee6..0563454 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Incluir anotação"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Incluir link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Não é possível adicionar links de outros perfis"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Gravador de tela"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
@@ -578,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nenhuma notificação nova"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"O recurso de atenuar notificações está ativo"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e alertas do disp. são reduzidos por até 2 min quando você recebe muitas notificações juntas."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e alertas são reduzidos por até 2 min quando você recebe muitas notificações juntas."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desativar"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueie p/ acessar notificações antigas"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerenciado pelo seu familiar responsável"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Adicionar"</string>
<string name="manage_users" msgid="1823875311934643849">"Gerenciar usuários"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificação não pode ser arrastada para a tela dividida"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi indisponível"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar a tela de bloqueio"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloqueie para personalizar a tela de bloqueio"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos do teclado e muito mais"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto de volta"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto de início"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tecla de ação"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para voltar, deslize para a esquerda ou direita usando 3 dedos em qualquer lugar do touchpad.\n\nVocê também pode usar o atalho de teclado Ação + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para acessar sua tela inicial a qualquer momento, deslize de baixo para cima na tela com três dedos."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Legal!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Você concluiu o gesto para acessar a tela inicial."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acessar os apps, pressione a tecla de ação no teclado."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Deslize para cima e pressione com três dedos. Toque para aprender outros gestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use o teclado para ver todos os apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pressione a tecla de ação a qualquer momento. Toque para aprender outros gestos."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"O recurso Escurecer a tela agora faz parte da barra de brilho"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Agora, na parte de cima, é possível usar o recurso Escurecer a tela, que diminui ainda mais o nível de brilho.\n\nIsso funciona melhor quando você está em um ambiente escuro."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Remover atalho de Escurecer a tela"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Atalho de Escurecer a tela removido. Use a barra normal para diminuir o brilho."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividade"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Acessibilidade"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitários"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacidade"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Fornecidos por apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Exibição"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecidos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e811fff..0b31bab 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Adicionar"</string>
<string name="manage_users" msgid="1823875311934643849">"Gerir utilizadores"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificação não pode ser arrastada para o ecrã dividido"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi indisponível"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo Prioridade"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar ecrã de bloqueio"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloqueie para personalizar o ecrã de bloqueio"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmara e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos de teclado e muito mais"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto para retroceder"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto para aceder ao ecrã principal"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tecla de ação"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluir"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para retroceder, deslize rapidamente para a esquerda ou direita com 3 dedos em qualquer parte do touchpad.\n\nPara o fazer, também pode usar o atalho de teclado Ação + ESC."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para aceder ao ecrã principal em qualquer altura, deslize rapidamente com 3 dedos de baixo para cima no ecrã."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Boa!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Concluiu o gesto para aceder ao ecrã principal."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para aceder às suas apps, prima a tecla de ação no teclado."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Deslize rapidamente para cima e mantenha premido com 3 dedos. Toque para aprender mais gestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use o teclado para ver todas as apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Prima a tecla de ação em qualquer altura. Toque para aprender mais gestos."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Agora, o escurecimento extra faz parte da barra do brilho"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Agora, pode tornar o ecrã ainda mais escuro reduzindo ainda mais o nível de brilho a partir da parte superior do ecrã.\n\nIsto funciona melhor quando está num ambiente escuro."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Remover atalho do escurecimento extra"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Atalho do escurecimento extra removido. Para reduzir o brilho, use a barra do brilho normal."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conetividade"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Acessibilidade"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitários"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacidade"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Disponibilizado por apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Ecrã"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecido"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 1331ee6..0563454 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Incluir anotação"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Incluir link"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Não é possível adicionar links de outros perfis"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Gravador de tela"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
@@ -578,7 +577,7 @@
<string name="empty_shade_text" msgid="8935967157319717412">"Sem notificações"</string>
<string name="no_unseen_notif_text" msgid="395512586119868682">"Nenhuma notificação nova"</string>
<string name="adaptive_notification_edu_hun_title" msgid="7790738150177329960">"O recurso de atenuar notificações está ativo"</string>
- <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e alertas do disp. são reduzidos por até 2 min quando você recebe muitas notificações juntas."</string>
+ <string name="adaptive_notification_edu_hun_text" msgid="7743367744129536610">"Volume e alertas são reduzidos por até 2 min quando você recebe muitas notificações juntas."</string>
<string name="go_to_adaptive_notification_settings" msgid="2423690125178298479">"Desativar"</string>
<string name="unlock_to_see_notif_text" msgid="7439033907167561227">"Desbloqueie p/ acessar notificações antigas"</string>
<string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Este dispositivo é gerenciado pelo seu familiar responsável"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Adicionar"</string>
<string name="manage_users" msgid="1823875311934643849">"Gerenciar usuários"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificação não pode ser arrastada para a tela dividida"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi indisponível"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modo de prioridade"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarme definido"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizar a tela de bloqueio"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Desbloqueie para personalizar a tela de bloqueio"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi indisponível"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Câmara bloqueada"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Câmera e microfone bloqueados"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfone bloqueado"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Aprenda gestos do touchpad, atalhos do teclado e muito mais"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto de volta"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto de início"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tecla de ação"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Concluído"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Voltar"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para voltar, deslize para a esquerda ou direita usando 3 dedos em qualquer lugar do touchpad.\n\nVocê também pode usar o atalho de teclado Ação + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para acessar sua tela inicial a qualquer momento, deslize de baixo para cima na tela com três dedos."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Legal!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Você concluiu o gesto para acessar a tela inicial."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tecla de ação"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para acessar os apps, pressione a tecla de ação no teclado."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Parabéns!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Deslize para cima e pressione com três dedos. Toque para aprender outros gestos."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Use o teclado para ver todos os apps"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pressione a tecla de ação a qualquer momento. Toque para aprender outros gestos."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"O recurso Escurecer a tela agora faz parte da barra de brilho"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Agora, na parte de cima, é possível usar o recurso Escurecer a tela, que diminui ainda mais o nível de brilho.\n\nIsso funciona melhor quando você está em um ambiente escuro."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Remover atalho de Escurecer a tela"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Atalho de Escurecer a tela removido. Use a barra normal para diminuir o brilho."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectividade"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Acessibilidade"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitários"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacidade"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Fornecidos por apps"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Exibição"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecidos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 35d0025..5edcaf1 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Adaugă în notă"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Include linkul"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Nu se pot adăuga linkuri din alte profiluri"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Recorder pentru ecran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificare în curs pentru o sesiune de înregistrare a ecranului"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Adaugă"</string>
<string name="manage_users" msgid="1823875311934643849">"Gestionează"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Notificarea nu acceptă tragerea pe ecranul împărțit"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi indisponibil"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modul Prioritate"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmă setată"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizează ecranul de blocare"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Deblochează pentru a personaliza ecranul de blocare"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Conexiune Wi-Fi indisponibilă"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Camera foto a fost blocată"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Camera foto și microfonul sunt blocate"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Microfonul a fost blocat"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Învață gesturi pentru touchpad, comenzi rapide de la tastatură și altele"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gestul Înapoi"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gestul Ecran de pornire"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tastă de acțiuni"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Gata"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Înapoi"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Pentru a reveni, glisează spre stânga sau spre dreapta cu trei degete oriunde pe touchpad.\n\nPoți folosi și comanda rapidă de la tastatură Action + ESC pentru aceasta."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Pentru a accesa oricând ecranul de pornire, glisează în sus cu trei degete din partea de jos a ecranului"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bravo!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ai finalizat gestul „accesează ecranul de pornire”."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasta de acțiuni"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Pentru a accesa aplicațiile, apasă tasta de acțiuni de pe tastatură."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Felicitări!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Glisează în sus și ține apăsat cu trei degete. Atinge ca să înveți mai multe gesturi."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Folosește-ți tastatura ca să vezi toate aplicațiile"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Apasă oricând tasta de acțiuni. Atinge ca să înveți mai multe gesturi."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Luminozitatea redusă suplimentar face acum parte din bara de luminozitate"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Poți reduce suplimentar luminozitatea ecranului dacă scazi nivelul de luminozitate din partea de sus a ecranului.\n\nAcest lucru funcționează cel mai bine într-un mediu întunecat."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Elimină comanda rapidă de luminozitate redusă suplimentar"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"S-a eliminat comanda rapidă de luminozitate redusă suplimentar. Ca să reduci luminozitatea, folosește bara obișnuită de luminozitate."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Conectivitate"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accesibilitate"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utilitare"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Confidențialitate"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Oferite de aplicații"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Ecran"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Necunoscută"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 2174dde..a1f1750 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Добавить"</string>
<string name="manage_users" msgid="1823875311934643849">"Управление пользователями"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Это уведомление нельзя перетаскивать между частями разделенного экрана."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Сеть Wi‑Fi недоступна"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Режим приоритета"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлен"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Настройки заблок. экрана"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Разблокируйте устройство, чтобы настроить заблокированный экран"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Функция Wi-Fi недоступна"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера заблокирована"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера и микрофон заблокированы"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон заблокирован"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Узнайте о жестах на сенсорной панели, сочетаниях клавиш и многом другом."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Жест \"назад\""</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Жест \"на главный экран\""</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Клавиша действия"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Чтобы вернуться назад, проведите по сенсорной панели тремя пальцами влево или вправо.\n\nВы также можете нажать клавишу действия + Esc."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Чтобы перейти на главный экран, проведите снизу вверх тремя пальцами."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Неплохо!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Вы выполнили жест для перехода на главный экран."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Клавиша действия"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Чтобы перейти к приложениям, нажмите клавишу действия на клавиатуре."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Готово!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Для этого проведите тремя пальцами вверх и удерживайте. Нажмите, чтобы посмотреть другие жесты."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Открывайте список всех приложений с помощью клавиатуры"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Для этого можно использовать клавишу действия. Нажмите, чтобы посмотреть другие жесты."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Дополнительно уменьшать яркость теперь можно через стандартный ползунок"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Чтобы дополнительно понизить яркость экрана, откройте настройки в его верхней части.\n\nРекомендуем использовать эту функцию, когда вокруг темно."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Удалить быструю команду для дополнительного уменьшения яркости"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Быстрая команда для дополнительного уменьшения яркости удалена. Чтобы изменить уровень яркости, воспользуйтесь стандартным ползунком яркости."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Подключение"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Специальные возможности"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Утилиты"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Конфиденциальность"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Приложения"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Экран"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Неизвестно"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 167e9cd..3dac0c5 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"සටහනට එක් කරන්න"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"සබැඳිය ඇතුළත් කරන්න"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"වෙනත් පැතිකඩවලින් සබැඳි එක් කළ නොහැක"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"තිර රෙකෝඩරය"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"එක් කරන්න"</string>
<string name="manage_users" msgid="1823875311934643849">"පරිශීලකයන් කළමනාකරණය කරන්න"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"මෙම දැනුම්දීම බෙදුම් තිරය වෙත ඇද ගෙන යාමට සහාය නොදක්වයි."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ලබා ගත නොහැකිය"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ප්රමුඛතා ප්රකාරය"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"සීනුව සකසන ලදි"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"අගුළු තිරය අභිරුචිකරණය කරන්න"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"අගුළු තිරය අභිරුචිකරණය කිරීමට අගුළු හරින්න"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ලද නොහැක"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"කැමරාව අවහිරයි"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"කැමරාව සහ මයික්රොෆෝනය අවහිරයි"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"මයික්රොෆෝනය අවහිරයි"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ස්පර්ශ පෑඩ් අභිනයන්, යතුරුපුවරු කෙටිමං සහ තවත් දේ ඉගෙන ගන්න"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ආපසු අභිනය"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"නිවෙස් අභිනය"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ක්රියා යතුර"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"නිමයි"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ආපස්සට යන්න"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"ආපසු යාමට, ස්පර්ශ පුවරුවවේ ඕනෑම තැනක ඇඟිලි තුනක් භාවිතයෙන් වමට හෝ දකුණට ස්වයිප් කරන්න.\n\nඔබට මේ සඳහා යතුරු පුවරු කෙටිමං ක්රියාව + ESC ද භාවිත කළ හැක."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ඕනෑම වේලාවක ඔබේ මුල් තිරයට යාමට, ඔබේ තිරයේ පහළ සිට ඇඟිලි තුනකින් ඉහළට ස්වයිප් කරන්න."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"කදිමයි!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"ඔබ මුල් පිටුවට යාමේ ඉංගිතය සම්පූර්ණ කළා."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ක්රියා යතුර"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ඔබේ යෙදුම් වෙත ප්රවේශ වීමට, ඔබේ යතුරු පුවරුවෙහි ක්රියා යතුර ඔබන්න."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"සුබ පැතුම්!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ඇඟිලි තුනක් භාවිතයෙන් ඉහළට ස්වයිප් කර අල්ලාගෙන සිටින්න. තව ඉංගිත දැන ගැනීමට තට්ටු කරන්න."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"සියලුම යෙදුම් බැලීමට ඔබේ යතුරු පුවරුව භාවිත කරන්න"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ඕනෑම අවස්ථාවක ක්රියාකාරී යතුර ඔබන්න. තව ඉංගිත දැන ගැනීමට තට්ටු කරන්න."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"තවත් අඳුර දැන් දීප්ත තීරුවේ කොටසකි"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ඔබේ තිරයේ ඉහළ සිට දීප්තියේ මට්ටම තවත් අඩු කිරීමෙන් ඔබට දැන් තිරය තවත් අඳුරු කළ හැක.\n\nඔබ අඳුරු පරිසරයක සිටින විට මෙය වඩාත් හොඳින් ක්රියා කරයි."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"තවත් අඳුරු කෙටිමඟ ඉවත් කරන්න"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"තවත් අඳුරු කෙටිමඟ ඉවත් කරන ලදි. ඔබේ දීප්තිය අඩු කිරීමට, සාමාන්ය දීප්ත තීරුව භාවිත කරන්න."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"සබැඳුම් හැකියාව"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ප්රවේශ්යතාව"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"උපයෝගිතා"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"රහස්යතාව"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"යෙදුම් මගින් සපයනු ලැබේ"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"සංදර්ශකය"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"නොදනී"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index dd872c2..166a95c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Pridať"</string>
<string name="manage_users" msgid="1823875311934643849">"Spravovať použ."</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Toto upozornenie nepodporuje presun na rozdelenú obrazovku"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nie je k dispozícii"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Režim priority"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Budík je nastavený"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Prispôsobiť uzamknutú obrazovku"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Uzamknutú obrazovku môžete prispôsobiť po odomknutí"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi‑Fi nie je k dispozícii"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokovaná"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofón sú blokované"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofón je blokovaný"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Naučte sa gestá touchpadu, klávesové skratky a ďalšie funkcie"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gesto prechodu späť"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gesto prechodu domov"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Akčný kláves"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Hotovo"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Prejsť späť"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ak chcete prejsť späť, potiahnite kdekoľvek na touchpade troma prstami doľava alebo doprava.\n\nMôžete použiť aj klávesovú skratku, teda akčný kláves + ESC."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Na plochu môžete kedykoľvek prejsť potiahnutím troma prstami zdola obrazovky."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Výborne!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Dokončili ste gesto na prechod na plochu."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Akčný kláves"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ak chcete získať prístup k aplikáciám, stlačte na klávesnici akčný kláves."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Blahoželáme!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Potiahnite troma prstami nahor a pridržte ich. Viac o gestách sa dozviete klepnutím."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Zobrazte si všetky aplikácie pomocou klávesnice"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Akčný kláves môžete stlačiť kedykoľvek. Viac o gestách sa dozviete klepnutím."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Mimoriadne stmavenie je teraz súčasťou posúvača na úpravu jasu"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Teraz môžete obrazovku mimoriadne stmaviť ešte ďalším znížením úrovne jasu v hornej časti obrazovky.\n\nNajlepšie to funguje v tmavom prostredí."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Odstrániť skratku mimoriadneho stmavenia"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Skratka mimoriadneho stmavenia bola odstránená. Ak chcete znížiť jas, použite bežný posúvač jasu."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Pripojenie"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Dostupnosť"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Utility"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Ochrana súkromia"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Poskytnuté aplikáciami"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Zobrazovanie"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznáme"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 01ca4e5..fa80b3a 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Dodaj"</string>
<string name="manage_users" msgid="1823875311934643849">"Upravljaj uporabnike"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"To obvestilo ne podpira vlečenja v razdeljen zaslon."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ni na voljo."</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prednostni način"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm je nastavljen."</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Prilagajanje zaklenjenega zaslona"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Odklenite za prilagajanje zaklenjenega zaslona"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ni na voljo."</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Fotoaparat je blokiran."</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Fotoaparat in mikrofon sta blokirana."</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon je blokiran."</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Učenje potez na sledilni ploščici, bližnjičnih tipk in drugega"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Poteza za pomik nazaj"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Poteza za začetni zaslon"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Gumb za dejanje"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Končano"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Nazaj"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Za pomik nazaj povlecite levo ali desno s tremi prsti kjer koli na sledilni ploščici.\n\nUporabite lahko tudi bližnjični tipki Action + ESC."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Za pomik na začetni zaslon lahko kadar koli s tremi prsti povlečete navzgor z dna zaslona."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Odlično!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Izvedli ste potezo za pomik na začetni zaslon."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tipka za dejanja"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Za dostop do aplikacij pritisnite tipko za dejanja na tipkovnici."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Čestitamo!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"S tremi prsti povlecite navzgor in pridržite. Dotaknite se, če želite spoznati več potez."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Uporaba tipkovnice za prikaz vseh aplikacij"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Kadar koli pritisnite tipko za dejanja. Dotaknite se, če želite spoznati več potez."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Funkcija Zelo zatemnjeno je zdaj del vrstice za uravnavanje svetlosti"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Zdaj lahko zelo zatemnite zaslon tako, da na vrhu zaslona dodatno zmanjšate raven svetlosti.\n\nTa funkcija najbolje deluje v temnem okolju."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Odstrani bližnjico do funkcije Zelo zatemnjeno"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Bližnjica do funkcije Zelo zatemnjeno je odstranjena. Če želite zmanjšati svetlost, uporabite običajno vrstico za uravnavanje svetlosti."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Povezljivost"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Dostopnost"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Orodja"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Zasebnost"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Zagotavljajo aplikacije"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Zaslon"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznano"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c4f8808..0b700f8 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Shto te shënimi"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Përfshi lidhjen"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Lidhjet nuk mund të shtohen nga profilet e tjera"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Regjistruesi i ekranit"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Regjistrimi i ekranit po përpunohet"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Njoftim i vazhdueshëm për një seancë regjistrimi të ekranit"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Shto"</string>
<string name="manage_users" msgid="1823875311934643849">"Menaxho përdoruesit"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Ky njoftim nuk mbështet zvarritjen tek ekrani i ndarë"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nuk ofrohet"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Modaliteti \"Me përparësi\""</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmi është caktuar"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Personalizo ekranin e kyçjes"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Shkyçe për të personalizuar ekranin e kyçjes"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi nuk ofrohet"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera u bllokua"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera dhe mikrofoni u bllokuan"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofoni u bllokua"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Mëso gjestet e bllokut me prekje, shkurtoret e tastierës etj."</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Gjesti i kthimit prapa"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Gjesti për të shkuar tek ekrani bazë"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Tasti i veprimit"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"U krye"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Kthehu prapa"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Për t\'u kthyer, rrëshqit shpejt majtas ose djathtas duke përdorur tri gishta kudo në bllokun me prekje.\n\nPër ta bërë këtë, mund të përdorësh gjithashtu shkurtoren e tastierës \"Action + ESC\"."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Për të shkuar tek ekrani bazë në çdo kohë, rrëshqit shpejt lart me tre gishta nga fundi i ekranit."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bukur!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"E ke përfunduar gjestin e kalimit tek ekrani bazë."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Tasti i veprimit"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Për t\'u qasur në aplikacionet e tua, shtyp tastin e veprimit në tastierë."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Urime!"</string>
@@ -1434,10 +1446,14 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Rrëshqit shpejt lart dhe mbaj shtypur me tre gishta. Trokit për të mësuar më shumë gjeste."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Përdor tastierën për të shikuar të gjitha aplikacionet"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Shtyp tastin e veprimit në çdo kohë. Trokit për të mësuar më shumë gjeste."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Modaliteti \"Shumë më i zbehtë\" tani është pjesë e shiritit të ndriçimit"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Tani mund ta bësh ekranin shumë më të zbehtë duke e ulur nivelin e ndriçimit edhe më tej nga kreu i ekranit.\n\nKjo funksionon më mirë kur je në një mjedis të errët."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Hiq shkurtoren e modalitetit \"Shumë më i zbehtë\""</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Shkurtorja e modalitetit \"Shumë më i zbehtë\" u hoq. Për të ulur ndriçimin, përdor shiritin e zakonshëm të ndriçimit."</string>
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
+ <skip />
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
+ <skip />
<!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
<skip />
<!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 66a4915..b1abb59 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Додај"</string>
<string name="manage_users" msgid="1823875311934643849">"Управљаj корисницима"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Ово обавештење не подржава превлачење на подељени екран"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WiFi није доступан"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Приоритетни режим"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Аларм је подешен"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Прилагоди закључани екран"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Откључајте да бисте прилагодили закључани екран"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"WiFi није доступан"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камера је блокирана"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камера и микрофон су блокирани"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Микрофон је блокиран"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Научите покрете за тачпед, тастерске пречице и друго"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Покрет за враћање"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Покрет за почетну страницу"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Тастер радњи"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Да бисте се вратили, превуците улево са три прста било где на тачпеду.\n\nМожете да користите и тастерску пречицу Alt + ESC за ово."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Да бисте отишли на почетни екран у било ком тренутку, превуците нагоре од дна екрана помоћу три прста."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Свака част!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Довршили сте покрет за повратак на почетну страницу."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Тастер радњи"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Да бисте приступили апликацијама, притисните тастер радњи на тастатури."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Честитамо!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Превуците нагоре и задржите са три прста. Додирните да бисте видели више покрета."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Користите тастатуру да бисте прегледали све апликације"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Притисните тастер радњи у било ком тренутку. Додирните да бисте видели више покрета."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Додатно затамњивање је сада део траке за осветљеност"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Сада можете додатно да затамните екран смањивањем нивоа осветљености при врху екрана. \n\nОво најбоље функционише када сте у тамном окружењу."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Уклони пречицу за додатно затамњивање"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Уклоњена је пречица за додатно затамњивање. Да бисте смањили осветљеност, користите уобичајену траку за осветљеност."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Повезивање"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Приступачност"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Услужне апликације"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Приватност"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Обезбеђују апликације"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Екран"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Непознато"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 5ec9e96..8817fe8 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Lägg till i anteckning"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Inkludera länk"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Det går inte att lägga till länkar från andra profiler"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Skärminspelare"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandlar skärminspelning"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Avisering om att skärminspelning pågår"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Lägg till"</string>
<string name="manage_users" msgid="1823875311934643849">"Välj användare"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Det går inte att dra den här aviseringen till delad skärm"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wifi är inte tillgängligt"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Prioritetsläge"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarmet är aktiverat"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Anpassa låsskärmen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Lås upp för att anpassa låsskärmen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wifi är inte tillgängligt"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kameran är blockerad"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kameran och mikrofonen är blockerade"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofonen är blockerad"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Lär dig rörelser för styrplattan, kortkommandon med mera"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Tillbaka-rörelse"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Rörelse för att öppna startskärmen"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Åtgärdstangent"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Klar"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Tillbaka"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Gå tillbaka genom att svepa åt vänster eller höger med tre fingrar var som helst på styrplattan.\n\nDu kan även använda kortkommandot Åtgärd + Esc."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Öppna startskärmen när som helst genom att svepa uppåt med tre fingrar från skärmens nederkant."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Bra!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Du är klar med rörelsen för att öppna startskärmen."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Åtgärdstangent"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Tryck på åtgärdstangenten på tangentbordet för att komma åt dina appar."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Grattis!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Svep uppåt med tre fingrar och håll kvar. Tryck för att lära dig fler rörelser."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Använd tangentbordet för att se alla appar"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Tryck på åtgärdstangenten när som helst. Tryck för att lära dig fler rörelser."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Extradimmat är nu en del av fältet för ljusstyrka"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Nu kan du göra skärmen extradimmad genom att sänka ljusstyrkan ännu mer från överst på skärmen.\n\nDetta fungerar bäst när omgivningen är mörk."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Ta bort kortkommandot för extradimmat"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Kortkommandot för extradimmat har tagits bort. Använd det vanliga fältet för ljusstyrka om du vill sänka ljusstyrkan."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Anslutning"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Tillgänglighet"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Verktyg"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Integritet"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Tillhandahålls av appar"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Skärm"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Okänt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index ababf70..28f677a 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Ongeza kwenye dokezo"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Jumuisha kiungo"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g> <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Huruhusiwi kuweka viungo kutoka kwenye wasifu mwingine"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Kinasa Skrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Weka"</string>
<string name="manage_users" msgid="1823875311934643849">"Dhibiti watumiaji"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Arifa hii haitumii utaratibu wa kuburuta ili kugawa skrini"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi haipatikani"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Hali ya kipaumbele"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Kengele imewekwa"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Wekea mapendeleo skrini iliyofungwa"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Fungua ili uweke mapendeleo ya skrini iliyofungwa"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi haipatikani"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera imezuiwa"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera na maikrofoni zimezuiwa"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Maikrofoni imezuiwa"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Jifunze kuhusu miguso ya padi ya kugusa, mikato ya kibodi na mengineyo"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Ishara ya kurudi nyuma"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Mguso wa kurudi kwenye skrini ya kwanza"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Kitufe cha vitendo"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Nimemaliza"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Rudi nyuma"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Telezesha vidole vitatu kushoto au kulia mahali popote kwenye padi ya kugusa ili urudi nyuma.\n\nUnaweza pia kutumia mikato ya kibodi ya Kitendo pamoja na ESC kutekeleza kitendo hiki."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ili uende kwenye skrini ya kwanza wakati wowote, telezesha vidole vitatu juu kutoka sehemu ya chini ya skrini yako."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Safi!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Umeweka ishara ya kwenda kwenye skrini ya kwanza."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Kitufe cha vitendo"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Bonyeza kitufe cha vitendo kwenye kibodi yako ili ufikie programu zako."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Hongera!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Telezesha vidole vitatu juu na ushikilie. Gusa ili upate maelezo kuhusu miguso zaidi."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Kutumia kibodi yako kuangalia programu zote"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Bonyeza kitufe cha vitendo wakati wowote. Gusa ili upate maelezo kuhusu miguso zaidi."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Kipunguza mwangaza zaidi sasa ni sehemu ya upau wa mwangaza"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Sasa unaweza kupunguza mwangaza zaidi kwa kupunguza kabisa kiwango cha mwangaza katika sehemu ya juu ya skrini yako.\n\nMipangilio hii hufanya kazi vyema zaidi ukiwa katika mazingira yenye giza."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Ondoa njia ya mkato ya kipunguza mwangaza zaidi"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Njia ya mkato ya kipunguza mwangaza zaidi imeondolewa. Tumia upau wa kawaida wa mwangaza ili upunguze mwangaza wako."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Muunganisho"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Ufikivu"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Vipengee"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Faragha"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Vinavyotolewa na programu"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Maonyesho"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Visivyojulikana"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 2a27b47..3efe7a5 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -26,6 +26,10 @@
<dimen name="keyguard_clock_top_margin">8dp</dimen>
<dimen name="keyguard_smartspace_top_offset">0dp</dimen>
+ <!-- New keyboard shortcut helper -->
+ <dimen name="shortcut_helper_width">864dp</dimen>
+ <dimen name="shortcut_helper_height">728dp</dimen>
+
<!-- QS-->
<dimen name="qs_panel_padding_top">16dp</dimen>
<dimen name="qs_panel_padding">24dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 54ab3c3..3b8e3c2 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"சேர்"</string>
<string name="manage_users" msgid="1823875311934643849">"பயனர்களை நிர்வகித்தல்"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"பிரிக்கப்பட்ட திரைக்குள் இந்த அறிவிப்பை இழுத்துவிட முடியாது"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"வைஃபை கிடைக்கவில்லை"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"முன்னுரிமைப் பயன்முறை"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"அலாரம் அமைக்கப்பட்டுள்ளது"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"பூட்டுத் திரையை பிரத்தியேகமாக்கு"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"பூட்டுத் திரையைப் பிரத்தியேகப்படுத்த அன்லாக் செய்யுங்கள்"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"வைஃபை கிடைக்கவில்லை"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"கேமரா தடுக்கப்பட்டுள்ளது"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"கேமராவும் மைக்ரோஃபோனும் தடுக்கப்பட்டுள்ளன"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"மைக்ரோஃபோன் தடுக்கப்பட்டுள்ளது"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"டச்பேட் சைகைகள், கீபோர்டு ஷார்ட்கட்கள் மற்றும் பலவற்றைத் தெரிந்துகொள்ளுங்கள்"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"பின்செல்வதற்கான சைகை"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"முகப்பிற்குச் செல்வதற்கான சைகை"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ஆக்ஷன் பட்டன்"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"முடிந்தது"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"பின்செல்"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"பின்செல்ல, உங்கள் டச்பேடில் எங்கு வேண்டுமானாலும் இடது அல்லது வலதுபுறமாக மூன்று விரல்களால் ஸ்வைப் செய்யவும்.\n\nஇதற்கு நீங்கள் கீபோர்டு ஷார்ட்கட் செயல்பாடுகள் + Esc பட்டனையும் பயன்படுத்தலாம்."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"எப்போது வேண்டுமானாலும் உங்கள் முகப்புத் திரைக்குச் செல்ல, மூன்று விரல்களால் திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்யவும்."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"அற்புதம்!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"முகப்புக்குச் செல்வதற்கான சைகையை நிறைவுசெய்துவிட்டீர்கள்."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ஆக்ஷன் பட்டன்"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"ஆப்ஸை அணுக உங்கள் கீபோர்டில் உள்ள ஆக்ஷன் பட்டனை அழுத்துங்கள்."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"வாழ்த்துகள்!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடிக்கவும். சைகைகள் குறித்து மேலும் அறிய தட்டவும்."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"அனைத்து ஆப்ஸையும் பார்க்க உங்கள் கீபோர்டைப் பயன்படுத்துங்கள்"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"எப்போது வேண்டுமானாலும் ஆக்ஷன் பட்டனை அழுத்தலாம். சைகைகள் குறித்து மேலும் அறிய தட்டவும்."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"\'மிகக் குறைவான வெளிச்சம்\' அம்சம் இப்போது ஒளிர்வுப் பட்டியின் ஒரு பகுதியாகும்"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"இப்போது உங்கள் திரையின் மேற்பகுதியில் ஒளிர்வு அளவைக் குறைப்பதன் மூலம் திரையை மிகக் குறைவான வெளிச்சத்திற்குக் கொண்டு வரலாம்.\n\nஇருட்டான சூழலில் இருக்கும்போது இது சிறப்பாகச் செயல்படும்."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"மிகக் குறைவான வெளிச்சத்திற்கான ஷார்ட்கட்டை அகற்று"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"மிகக் குறைவான வெளிச்சத்திற்கான ஷார்ட்கட் அகற்றப்பட்டது. உங்கள் ஒளிர்வைக் குறைக்க, வழக்கமான ஒளிர்வுப் பட்டியைப் பயன்படுத்துங்கள்."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"இணைப்புநிலை"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"மாற்றுத்திறன் வசதி"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"யூட்டிலிட்டி சேவைகள்"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"தனியுரிமை"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ஆப்ஸ் வழங்குபவை"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"டிஸ்ப்ளே"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"தெரியவில்லை"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 2c4109a..84fc147 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -125,7 +125,7 @@
<string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"స్క్రీన్ రికార్డింగ్ చేయబడుతోంది"</string>
<string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"స్క్రీన్, ఆడియో రికార్డింగ్ చేయబడుతున్నాయి"</string>
<string name="screenrecord_taps_label" msgid="1595690528298857649">"స్క్రీన్పై తాకే స్థానాలను చూపండి"</string>
- <string name="screenrecord_stop_label" msgid="72699670052087989">"ఆపివేయి"</string>
+ <string name="screenrecord_stop_label" msgid="72699670052087989">"ఆపివేయండి"</string>
<string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయండి"</string>
<string name="screenrecord_save_title" msgid="1886652605520893850">"స్క్రీన్ రికార్డింగ్ సేవ్ చేయబడింది"</string>
<string name="screenrecord_save_text" msgid="3008973099800840163">"చూడటానికి ట్యాప్ చేయండి"</string>
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"జోడించండి"</string>
<string name="manage_users" msgid="1823875311934643849">"యూజర్లను మేనేజ్ చేయండి"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"ఈ నోటిఫికేషన్ స్ప్లిట్ స్క్రీన్కు లాగడాన్ని సపోర్ట్ చేయదు"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi అందుబాటులో లేదు"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ముఖ్యమైన ఫైల్స్ మోడ్"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"అలారం సెట్ చేశాను"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"లాక్ స్క్రీన్ అనుకూలంగా మార్చండి"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"లాక్ స్క్రీన్ను అనుకూలంగా మార్చుకోవడానికి అన్లాక్ చేయండి"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi అందుబాటులో లేదు"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"కెమెరా బ్లాక్ చేయబడింది"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"కెమెరా, మైక్రోఫోన్ బ్లాక్ చేయబడ్డాయి"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"మైక్రోఫోన్ బ్లాక్ చేయబడింది"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"టచ్ప్యాడ్ సంజ్ఞలు, కీబోర్డ్ షార్ట్కట్లు, అలాగే మరిన్నింటిని గురించి తెలుసుకోండి"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"వెనుకకు పంపే సంజ్ఞ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"హోమ్కు పంపే సంజ్ఞ"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"యాక్షన్ కీ"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"పూర్తయింది"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"వెనుకకు"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"వెనుకకు వెళ్లడానికి, టచ్ప్యాడ్లో ఎక్కడైనా మూడు వేళ్లను ఉపయోగించి ఎడమ లేదా కుడి వైపునకు స్వైప్ చేయండి.\n\nమీరు దీని కోసం + ESC కీబోర్డ్ షార్ట్కట్ యాక్షన్ను కూడా ఉపయోగించవచ్చు."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ఏ సమయంలోనైనా మీ మొదటి స్క్రీన్కు వెళ్లడానికి, మీ స్క్రీన్ కింది నుండి మూడు వేళ్లతో పైకి స్వైప్ చేయండి."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"సూపర్!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"మొదటి స్క్రీన్కు వెళ్ళడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్ను మీరు పూర్తి చేశారు."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"యాక్షన్ కీ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"మీ యాప్లను యాక్సెస్ చేయడానికి, మీ కీబోర్డ్లో యాక్షన్ కీని నొక్కండి."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"అభినందనలు!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"మూడు వేళ్లతో పైకి స్వైప్ చేసి, హోల్డ్ చేయండి. మరిన్ని సంజ్ఞల గురించి తెలుసుకోవడానికి ట్యాప్ చేయండి."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"యాప్లన్నింటినీ చూడటానికి మీ కీబోర్డ్ను ఉపయోగించండి"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"ఏ సమయంలోనైనా యాక్షన్ కీని నొక్కండి. మరిన్ని సంజ్ఞల గురించి తెలుసుకోవడానికి ట్యాప్ చేయండి."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"కాంతిని మరింత డిమ్ చేసే ఫీచర్ ఇప్పుడు బ్రైట్నెస్ బార్లో ఒక భాగం"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"మీరు ఇప్పుడు మీ స్క్రీన్ పైభాగం నుండి బ్రైట్నెస్ స్థాయిని తగ్గించడం ద్వారా కూడా స్క్రీన్ కాంతిని మరింత డిమ్ చేయవచ్చు.\n\nమీరు డార్క్ ఎన్విరాన్మెంట్లో ఉన్నప్పుడు కూడా ఇది బాగా పని చేస్తుంది."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"కాంతిని మరింత డిమ్ చేసే షార్ట్కట్ను తీసివేయండి"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"కాంతిని మరింత డిమ్ చేసే షార్ట్కట్ తీసివేయబడింది. మీ బ్రైట్నెస్ను తగ్గించడానికి, సాధారణ బ్రైట్నెస్ బార్ను ఉపయోగించండి."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"కనెక్టివిటీ"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"యుటిలిటీలు"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"గోప్యత"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"యాప్ల ద్వారా అందించబడినవి"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"డిస్ప్లే"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"తెలియదు"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 20e730c..1d7a782 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"เพิ่ม"</string>
<string name="manage_users" msgid="1823875311934643849">"จัดการผู้ใช้"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"การแจ้งเตือนนี้ไม่รองรับการลากเพื่อแยกหน้าจอ"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"ใช้ Wi‑Fi ไม่ได้"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"โหมดลำดับความสำคัญ"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"ตั้งปลุกแล้ว"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"ปรับแต่งหน้าจอล็อก"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"ปลดล็อกเพื่อปรับแต่งหน้าจอล็อก"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi ไม่พร้อมใช้งาน"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"กล้องถูกบล็อกอยู่"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"กล้องและไมโครโฟนถูกบล็อกอยู่"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"ไมโครโฟนถูกบล็อกอยู่"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ดูข้อมูลเกี่ยวกับท่าทางสัมผัสของทัชแพด แป้นพิมพ์ลัด และอื่นๆ"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"ท่าทางสัมผัสสำหรับย้อนกลับ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ท่าทางสัมผัสสำหรับหน้าแรก"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ปุ่มดำเนินการ"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"เสร็จสิ้น"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"ย้อนกลับ"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"หากต้องการย้อนกลับ ให้ใช้ 3 นิ้วปัดไปทางซ้ายหรือขวาที่ใดก็ได้บนทัชแพด\n\nหรือใช้การดำเนินการแป้นพิมพ์ลัด + ESC ได้เช่นเดียวกัน"</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"ใช้ 3 นิ้วปัดขึ้นจากด้านล่างของหน้าจอเพื่อไปที่หน้าจอหลักได้ทุกเมื่อ"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"ดีมาก"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ปุ่มดำเนินการ"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"หากต้องการเข้าถึงแอป ให้กดปุ่มดำเนินการบนแป้นพิมพ์"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"ยินดีด้วย"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"ใช้ 3 นิ้วปัดขึ้นแล้วค้างไว้ แตะเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับท่าทางสัมผัสต่างๆ"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"ใช้แป้นพิมพ์เพื่อดูแอปทั้งหมด"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"กดปุ่มดำเนินการได้ทุกเมื่อ แตะเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับท่าทางสัมผัสต่างๆ"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"ตอนนี้การหรี่แสงเพิ่มเติมเป็นส่วนหนึ่งของแถบความสว่างแล้ว"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"ตอนนี้คุณสามารถหรี่แสงหน้าจอเพิ่มเติมได้โดยลดระดับความสว่างจากด้านบนของหน้าจอมากขึ้น\n\nฟีเจอร์นี้จะทำงานได้ดีเมื่อคุณอยู่ในที่มืด"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"นำทางลัดหรี่แสงเพิ่มเติมออก"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"นำทางลัดหรี่แสงเพิ่มเติมออกแล้ว หากต้องการลดความสว่าง ให้ใช้แถบความสว่างปกติ"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"การเชื่อมต่อ"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"การช่วยเหลือพิเศษ"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"ยูทิลิตี"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"ความเป็นส่วนตัว"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ให้บริการโดยแอป"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"จอแสดงผล"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ไม่ทราบ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 0bef743..00be27b 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Magdagdag"</string>
<string name="manage_users" msgid="1823875311934643849">"Pamahalaan ang mga user"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Hindi sinusuportahan ng notification na ito ang pag-drag sa split screen"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Hindi available ang Wi‑Fi"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Priority mode"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Nakatakda ang alarm"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"I-customize ang lock screen"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"I-unlock para i-customize ang lock screen"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Hindi available ang Wi-Fi"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Naka-block ang camera"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Naka-block ang camera at mikropono"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Naka-block ang mikropono"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Matuto ng mga galaw sa touchpad, keyboard shortcut, at higit pa"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Galaw para bumalik"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Galaw para sa Home"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Action key"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tapos na"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Bumalik"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Para bumalik, mag-swipe pakaliwa o pakanan gamit ang tatlong daliri saanman sa touchpad.\n\nPuwede mo ring gamitin ang keyboard shortcut na Action + ESC para dito."</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Para pumunta sa iyong home screen anumang oras, mag-swipe pataas gamit ang tatlong daliri mula sa ibaba ng screen. mo."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Magaling!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Nakumpleto mo na ang galaw para pumunta sa home."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Action key"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Para ma-access ang iyong mga app, pindutin ang action key sa keyboard mo."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Binabati kita!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Mag-swipe pataas at i-hold gamit ang tatlong daliri. I-tap para matuto pa tungkol sa mga galaw."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Gamitin ang iyong keyboard para tingnan ang lahat ng app"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Pindutin ang action key kahit kailan. I-tap para matuto pa tungkol sa mga galaw."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Bahagi na ng brightness bar ang extra dim"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Puwede mo nang gawing extra dim ang screen sa pamamagitan ng pagpapababa ng level ng liwanag nang higit pa mula sa itaas ng iyong screen.\n\nPinakamahusay itong gumagana kapag nasa madilim na kapaligiran ka."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Alisin ang shortcut ng extra dim"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Inalis ang shortcut ng extra dim. Para bawasan ang liwanag, gamitin ang karaniwang bar ng liwanag."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Pagkakonekta"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Accessibility"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Mga Utility"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Privacy"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Ibinibigay ng mga app"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Display"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Hindi Alam"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 060ecd1..0031687 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Nota ekle"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Bağlantıyı dahil et"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Başka profillerden bağlantı eklenemez"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekran Kaydedicisi"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Ekle"</string>
<string name="manage_users" msgid="1823875311934643849">"Kullanıcıları yönet"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Bu bildirim bölünmüş ekrana sürüklemeyi desteklemiyor"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Kablosuz kullanılamıyor"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Öncelik modu"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Alarm kuruldu"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Kilit ekranını özelleştir"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Kilit ekranını özelleştirmek için kilidi açın"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Kablosuz bağlantı kullanılamıyor"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera engellendi"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ve mikrofon engellendi"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon engellendi"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Dokunmatik alan hareketlerini, klavye kısayollarını ve daha fazlasını öğrenin"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Geri hareketi"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Ana sayfa hareketi"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Eylem tuşu"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Bitti"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Geri dön"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Geri dönmek için dokunmatik alanın herhangi bir yerinde üç parmağınızla sola veya sağa kaydırın.\n\nDilerseniz işlem düğmesi + Esc klavye kısayolunu kullanarak da geri dönebilirsiniz."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"İstediğiniz zaman ana ekrana gitmek için üç parmağınızla ekranınızın altından yukarı doğru kaydırın."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Güzel!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ana ekrana git hareketini tamamladınız."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Eylem tuşu"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Uygulamalarınıza erişmek için klavyenizdeki eylem tuşuna basın."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tebrikler!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Üç parmağınızla yukarı kaydırıp basılı tutun. Daha fazla hareket öğrenmek için dokunun."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Tüm uygulamaları görüntülemek için klavyenizi kullanın"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"İstediğiniz zaman eylem tuşuna basın. Daha fazla hareket öğrenmek için dokunun."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Ekstra loş özelliği, parlaklık çubuğuna eklendi"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Artık ekranınızın üst kısmından parlaklık seviyesini daha da düşürerek ekranı ekstra loş hale getirebilirsiniz.\n\nBu özellik, karanlık ortamdayken en iyi sonucu verir."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Ekstra loş kısayolunu kaldır"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Ekstra loş kısayolu kaldırıldı. Parlaklık seviyesini düşürmek için normal parlaklık çubuğunu kullanın."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Bağlantı"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Erişilebilirlik"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Yardımcı programlar"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Gizlilik"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Uygulamalar tarafından sağlanır"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Ekran"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Bilinmiyor"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index ae07ae2..715b179 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Додати до примітки"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Додати посилання"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Не можна додавати посилання з інших профілів"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Запис відео з екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Додати"</string>
<string name="manage_users" msgid="1823875311934643849">"Керувати користувачами"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Це сповіщення не підтримує режим розділеного екрана"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Мережа Wi-Fi недоступна"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Режим пріоритету"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Будильник установлено"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Налаштувати заблокований екран"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Розблокуйте, щоб налаштувати заблокований екран"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Мережа Wi-Fi недоступна"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камеру заблоковано"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Камеру й мікрофон заблоковано"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Мікрофон заблоковано"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Жести для сенсорної панелі, комбінації клавіш тощо: докладніше"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Жест \"Назад\""</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Жест переходу на головний екран"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Клавіша дії"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Готово"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Назад"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Щоб перейти назад, проведіть трьома пальцями вліво або вправо по сенсорній панелі.\n\nТакож можна скористатися комбінацією \"клавіша дії\" + ESC."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Щоб будь-коли перейти на головний екран, проведіть трьома пальцями вгору від нижнього краю екрана."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Чудово!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ви виконали жест переходу на головний екран."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Клавіша дії"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Щоб переглянути додатки, натисніть клавішу дії на клавіатурі."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Вітаємо!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Проведіть трьома пальцями вгору й утримуйте їх на екрані. Натисніть, щоб дізнатися про інші жести."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Щоб переглянути всі додатки, використовуйте клавіатуру"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Будь-коли натисніть клавішу дії. Натисніть, щоб дізнатися про інші жести."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Тепер на панелі регулювання яскравості є функція додаткового зменшення яскравості"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Тепер ви можете зробити екран ще темнішим, додатково зменшуючи рівень яскравості вгорі екрана.\n\nНайкраще ця функція працює, коли ви перебуваєте в темному місці."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Видалити комбінацію клавіш для додаткового зменшення яскравості"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Комбінацію клавіш для додаткового зменшення яскравості видалено. Щоб зменшити яскравість, використовуйте стандартну панель регулювання."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Обмін даними"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Функції доступності"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Утиліти"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Конфіденційність"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Надано додатками"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Екран"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Невідомо"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 5d1f66e..78a7f428 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1289,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"شامل کریں"</string>
<string name="manage_users" msgid="1823875311934643849">"صارفین کا نظم کریں"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"یہ اطلاع اسپلٹ اسکرین پر گھسیٹنے کو سپورٹ نہیں کرتی ہے"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi-Fi دستیاب نہیں ہے"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"ترجیحی وضع"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"الارم سیٹ ہوگیا"</string>
@@ -1345,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"مقفل اسکرین کو حسب ضرورت بنائیں"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"مقفل اسکرین کو حسب ضرورت بنانے کے لیے غیر مقفل کریں"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi دستیاب نہیں ہے"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"کیمرا مسدود ہے"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"کیمرا اور مائیکروفون مسدود ہے"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"مائیکروفون مسدود ہے"</string>
@@ -1400,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"ٹچ پیڈ کے اشارے، کی بورڈ شارٹ کٹس اور مزید جانیں"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"پیچھے جانے کا اشارہ"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"ہوم کا اشارہ"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"ایکشن کلید"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"ہو گیا"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"واپس جائیں"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"واپس جانے کے لیے، ٹچ پیڈ پر کہیں بھی تین انگلیوں کی مدد سے دائیں یا بائیں سوائپ کریں۔\n\nآپ اس کیلئے کی بورڈ شارٹ کٹ ایکشن + Esc کا بھی استعمال کر سکتے ہیں۔"</string>
@@ -1410,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"کسی بھی وقت اپنی ہوم اسکرین پر جانے کے لیے، تین انگلیوں کی مدد سے اپنی اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں۔"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"عمدہ!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"آپ نے ہوم پر جانے کا اشارہ مکمل کر لیا۔"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"ایکشن کلید"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"اپنی ایپس تک رسائی حاصل کرنے کے لیے، اپنے کی بورڈ پر ایکشن کلید کو دبائیں۔"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"مبارکباد!"</string>
@@ -1433,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"تین انگلیوں سے اوپر کی طرف سوائپ کریں اور دبائے رکھیں۔ مزید اشارے جاننے کے لیے تھپتھپائیں۔"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"سبھی ایپس دیکھنے کے لیے اپنے کی بورڈ کا استعمال کریں"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"کسی بھی وقت ایکشن کلید دبائیں۔ مزید اشارے جاننے کے لیے تھپتھپائیں۔"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"اضافی دھندلا اب چمک بار کا حصہ ہے"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"آپ اپنی اسکرین کے اوپری حصے سے چمکیلے پن لیول کو مزید کم کر کے اپنی اسکرین کو اضافی دھندلی بنا سکتے ہیں۔\n\nجب آپ تاریک ماحول میں ہوتے ہیں تو یہ بہتر کام کرتا ہے۔"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"اضافی دھندلا شارٹ کٹ کو ہٹائیں"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"اضافی دھندلا شارٹ کٹ کو ہٹا دیا گیا۔ اپنا چمکیلا پن کم کرنے کیلئے، ریگولر چمک بار کا استعمال کریں"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"کنیکٹویٹی"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"ایکسیسبیلٹی"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"یوٹیلیٹیز"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"رازداری"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"ایپس کے ذریعہ فراہم کردہ"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"ڈسپلے"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"نامعلوم"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index af35adf..51cf8b5 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Qaydga qoʻshish"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Havolani kiritish"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g>, <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Boshqa profillardan havola kiritish mumkin emas"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Ekranni yozib olish"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran yozib olinmoqda"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Kiritish"</string>
<string name="manage_users" msgid="1823875311934643849">"Foyd-ni boshqarish"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Bu bildirishnoma ikkiga ajratilgan ekranda ishlamaydi."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ishlamayapti"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Imtiyozli rejim"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Signal oʻrnatildi"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Ekran qulfini moslash"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ekran qulfini sozlash uchun qulfni oching"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi mavjud emas"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera bloklangan"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera va mikrofon bloklangan"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Mikrofon bloklangan"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Sensorli panel ishoralari, tezkor tugmalar va boshqalar haqida"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Orqaga qaytish ishorasi"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Asosiy ekran ishorasi"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Amal tugmasi"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Tayyor"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Orqaga qaytish"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ortga qaytish uchun sensorli panelda uchta barmoqni chapga yoki oʻngga suring.\n\nBuning uchun Action + ESC tezkor tugmalaridan ham foydalanishingiz mumkin."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Istalgan vaqtda bosh ekranga oʻtish uchun ekranning pastidan uchta barmoq bilan tepaga suring."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Yaxshi!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Bosh ekranni ochish ishorasi darsini tamomladingiz."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Amal tugmasi"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ilovalarga kirish uchun klaviaturadagi amal tugmasini bosing"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Tabriklaymiz!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Uchta barmoq bilan tepaga surib, bosib turing. Boshqa ishoralar bilan tanishish uchun bosing."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Klaviatura orqali barcha ilovalarni koʻrish"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Amal tugmasini istalganda bosing. Boshqa ishoralar bilan tanishish uchun bosing."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Juda xira endi yorqinlik panelida joylashgan"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Endi yorqinlik darajasini ekranning yuqori qismidan yanada pasaytirish orqali ekranni yanada xiralashtirishingiz mumkin.\n\nBu qorongʻi muhitda eng yaxshi ishlaydi."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Juda xira yorligʻini olib tashlash"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Juda xira yorligʻi olib tashlandi. Yorqinlikni pasaytirish uchun oddiy yorqinlik panelidan foydalaning."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Aloqa"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Qulayliklar"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Vositalar"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Maxfiylik"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Ilovalarga tegishli"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Ekran"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Noaniq"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index b7cd6b0..fb9abd7 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Thêm vào ghi chú"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Thêm đường liên kết"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Không thể thêm đường liên kết từ các hồ sơ khác"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Trình ghi màn hình"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Đang xử lý video ghi màn hình"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Thông báo đang diễn ra về phiên ghi màn hình"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Thêm"</string>
<string name="manage_users" msgid="1823875311934643849">"Quản lý ng.dùng"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Thông báo này không hỗ trợ thao tác kéo để chia đôi màn hình"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Không có Wi‑Fi"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Chế độ ưu tiên"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"Đã đặt chuông báo"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Tuỳ chỉnh màn hình khoá"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Mở khoá để tuỳ chỉnh màn hình khoá"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Không có Wi-Fi"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Máy ảnh bị chặn"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Máy ảnh và micrô bị chặn"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Micrô bị chặn"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Tìm hiểu về cử chỉ trên bàn di chuột, phím tắt và nhiều mục khác"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Cử chỉ quay lại"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Cử chỉ chuyển đến màn hình chính"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Phím hành động"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Xong"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Quay lại"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Để quay lại, hãy dùng 3 ngón tay vuốt sang trái hoặc sang phải ở vị trí bất kỳ trên bàn di chuột.\n\nBạn cũng có thể dùng phím tắt Hành động + ESC cho thao tác này."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Để chuyển đến màn hình chính bất cứ lúc nào, hãy dùng 3 ngón tay vuốt lên từ cuối màn hình lên."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Tốt lắm!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Bạn đã thực hiện xong cử chỉ chuyển đến màn hình chính."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Phím hành động"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Để truy cập vào các ứng dụng của bạn, hãy nhấn phím hành động trên bàn phím."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Xin chúc mừng!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Dùng 3 ngón tay vuốt lên và giữ. Hãy nhấn để tìm hiểu các cử chỉ khác."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Sử dụng bàn phím để xem tất cả ứng dụng"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Nhấn phím hành động bất cứ lúc nào. Hãy nhấn để tìm hiểu các cử chỉ khác."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Chế độ siêu tối hiện đã có trên thanh độ sáng"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Giờ đây, bạn có thể đặt màn hình ở chế độ siêu tối bằng cách giảm thêm độ sáng từ đầu màn hình.\n\nChế độ này hoạt động hiệu quả nhất khi bạn ở trong một môi trường tối."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Xoá lối tắt của chế độ siêu tối"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Đã xoá lối tắt của chế độ siêu tối. Để giảm độ sáng, hãy dùng thanh độ sáng như thông thường."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Khả năng kết nối"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Hỗ trợ tiếp cận"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Phần mềm tiện ích"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Quyền riêng tư"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Do các ứng dụng cung cấp"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Hiển thị"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Không xác định"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index a329965..d311aa3 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"添加到备注中"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"包括链接"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"无法添加来自其他个人资料的链接"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"屏幕录制器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"添加"</string>
<string name="manage_users" msgid="1823875311934643849">"管理用户"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"此通知不支持拖动到分屏中"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"WLAN 已关闭"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"优先模式"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"闹钟已设置"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"自定义锁屏"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"解锁以自定义锁定屏幕"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"没有 WLAN 连接"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"已禁用摄像头"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已禁用摄像头和麦克风"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"已禁用麦克风"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"了解触控板手势、键盘快捷键等"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"返回手势"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"主屏幕手势"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"快捷操作按键"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"如要返回,请使用三根手指在触控板上的任意位置左滑或右滑。\n\n您也可以使用键盘快捷操作键 + ESC 键进行返回。"</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"若要随时进入主屏幕,请用三根手指从屏幕的底部向上滑动。"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"很好!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"您完成了“前往主屏幕”手势教程。"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"快捷操作按键"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"如要访问您的应用,请按下键盘上的快捷操作按键。"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"恭喜!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"用三根手指向上滑动并按住。点按即可了解更多手势。"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"使用键盘查看所有应用"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"您可随时按下快捷操作按键。点按即可了解更多手势。"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"“极暗”功能现已在亮度条中"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"现在,您可从屏幕顶部进一步调低亮度,将屏幕调成极暗。\n\n此功能在昏暗环境中效果最佳。"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"移除“极暗”快捷方式"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"已移除“极暗”快捷方式。如要调低亮度,请使用常规亮度条。"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"连接"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"无障碍功能"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"实用程序"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"隐私设置"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"由应用提供"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"显示"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"未知"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 73bfbe6c..91ae846 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"新增至筆記"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"加入連結"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"無法新增來自其他設定檔的連結"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"螢幕錄影機"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示錄影畫面工作階段通知"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"新增"</string>
<string name="manage_users" msgid="1823875311934643849">"管理使用者"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"此通知無法拖曳到分割螢幕中。"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi 已關閉"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先模式"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"已設定鬧鐘"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"自訂上鎖畫面"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"解鎖後即可自訂上鎖畫面"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"無法連線至 Wi-Fi"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"已封鎖相機"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已封鎖相機和麥克風"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"已封鎖麥克風"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"瞭解觸控板手勢、鍵盤快速鍵等等"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"返去手勢"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"主畫面手勢"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"快捷操作鍵"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"用三隻手指在觸控板上任何一處向左或向右滑動即可返回。\n\n你也可使用鍵盤快速鍵 Action 鍵 + Esc 鍵執行此操作。"</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"只要用三隻手指從螢幕底部向上滑動,隨時可以返回主畫面。"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"做得好!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"你已完成「返回主畫面」手勢的教學課程。"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"快捷操作鍵"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"如要存取應用程式,請在鍵盤上按下快捷操作鍵。"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"恭喜!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"用三隻手指向上滑動並按住。輕按即可瞭解更多手勢。"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"使用鍵盤查看所有應用程式"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"隨時按下快捷操作鍵。輕按即可瞭解更多手勢。"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"亮度列現已加入超暗功能"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"而家喺螢幕頂部進一步校低亮度,就可以令螢幕變得超暗\n\n呢個功能喺陰暗環境之下嘅效果最好"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"移除超暗功能快速鍵"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"超暗功能快速鍵已移除。如要降低亮度,請使用一般的亮度列。"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"裝置連接"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"無障礙功能"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"實用程式"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"私隱"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"由應用程式提供"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"螢幕"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 46847fc..93a99e6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"新增至記事本"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"包含連結"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"無法新增其他設定檔中的連結"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"螢幕錄影器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示螢幕畫面錄製工作階段通知"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"新增"</string>
<string name="manage_users" msgid="1823875311934643849">"管理使用者"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"這項通知無法拖曳到分割畫面中。"</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi 已關閉"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"優先模式"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"鬧鐘設定成功"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"自訂螢幕鎖定畫面"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"解鎖後即可自訂螢幕鎖定畫面"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"無法連上 Wi-Fi"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"已封鎖攝影機"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"已封鎖攝影機和麥克風"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"已封鎖麥克風"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"學習觸控板手勢、鍵盤快速鍵等"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"返回手勢"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"主畫面手勢"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"快捷操作鍵"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"完成"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"返回"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"如要返回,請在觸控板的任何位置上用三指向左或向右滑動。\n\n使用快捷操作鍵 + ESC 鍵 (鍵盤快速鍵) 也可以返回。"</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"用 3 指從螢幕底部向上滑動,就能隨時返回主畫面。"</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"太棒了!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"你已完成「返回主畫面」手勢的教學課程。"</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"快捷操作鍵"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"如要存取應用程式,請按下鍵盤上的快捷操作鍵。"</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"恭喜!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"用三指向上滑動並按住。輕觸即可進一步瞭解手勢。"</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"使用鍵盤查看所有應用程式"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"你隨時可以按下快捷操作鍵。輕觸即可進一步瞭解手勢。"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"「超暗」已移到亮度列"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"現在只要在螢幕頂端將亮度設定調得更低,就能讓螢幕變得更暗。\n\n這項設定最適合在昏暗環境下使用。"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"移除「超暗」捷徑"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"「超暗」捷徑已移除。如要調低亮度,請使用一般的亮度列。"</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"連線"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"無障礙"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"公用程式"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"隱私權"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"由應用程式提供"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"螢幕"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index dbfb926..9fc1166 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -105,8 +105,7 @@
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Engeza kunothi"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Faka ilinki"</string>
<string name="backlinks_duplicate_label_format" msgid="558445128952827926">"<xliff:g id="APPNAME">%1$s</xliff:g> <xliff:g id="FREQUENCYCOUNT">(%2$d)</xliff:g>"</string>
- <!-- no translation found for backlinks_cross_profile_error (1355798585727802282) -->
- <skip />
+ <string name="backlinks_cross_profile_error" msgid="1355798585727802282">"Amalinki awakwazi ukufakwa ukusuka kwamanye amaphrofayela"</string>
<string name="screenrecord_title" msgid="4257171601439507792">"Okokuqopha iskrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Icubungula okokuqopha iskrini"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Isaziso esiqhubekayo seseshini yokurekhoda isikrini"</string>
@@ -1290,6 +1289,8 @@
<string name="add" msgid="81036585205287996">"Faka"</string>
<string name="manage_users" msgid="1823875311934643849">"Phatha abasebenzisi"</string>
<string name="drag_split_not_supported" msgid="7173481676120546121">"Lesi saziso asikusekeli ukuhudulela ekuhlukaniseni isikrini."</string>
+ <!-- no translation found for dream_overlay_location_active (6484763493158166618) -->
+ <skip />
<string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"I-Wi-Fi ayitholakali"</string>
<string name="dream_overlay_status_bar_priority_mode" msgid="5428462123314728739">"Imodi ebalulekile"</string>
<string name="dream_overlay_status_bar_alarm_set" msgid="566707328356590886">"I-alamu isethiwe"</string>
@@ -1346,6 +1347,8 @@
<string name="lock_screen_settings" msgid="6152703934761402399">"Yenza ngokwezifiso ukukhiya isikrini"</string>
<string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Vula ukuze wenze ukuvala isikrini ngendlela oyifisayo"</string>
<string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"I-Wi-Fi ayitholakali"</string>
+ <!-- no translation found for location_active_dream_overlay_content_description (6208885541020673916) -->
+ <skip />
<string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Ikhamera ivinjiwe"</string>
<string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Ikhamera nemakrofoni zivinjiwe"</string>
<string name="microphone_blocked_dream_overlay_content_description" msgid="5466897982130007033">"Imakrofoni ivinjiwe"</string>
@@ -1401,7 +1404,8 @@
<string name="launch_keyboard_touchpad_tutorial_notification_content" msgid="1780725168171929365">"Funda ukunyakaza kwephedi yokuthinta, izinqamuleli zamakhibhodi, nokuningi"</string>
<string name="touchpad_tutorial_back_gesture_button" msgid="2746834288077265946">"Ukunyakazisa umzimba kwangemuva"</string>
<string name="touchpad_tutorial_home_gesture_button" msgid="7640544867625955304">"Ukunyakazisa umzimba kwasekhaya"</string>
- <string name="touchpad_tutorial_action_key_button" msgid="3220074511852927267">"Inkinobho yokufinyelela"</string>
+ <!-- no translation found for touchpad_tutorial_recent_apps_gesture_button (8919227647650347359) -->
+ <skip />
<string name="touchpad_tutorial_done_button" msgid="176168488821755503">"Kwenziwe"</string>
<string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"Buyela emuva"</string>
<string name="touchpad_back_gesture_guidance" msgid="6263750214998421587">"Ukuze ubuyele emuva, swayiphela kwesokunxele noma kwesokudla usebenzisa iminwe emithathu noma yikuphi ephedini yokuthinta.\n\nUngasebenzisa nesinqamuleli sekhibhodi Isenzo + ESC kulokhu."</string>
@@ -1411,6 +1415,14 @@
<string name="touchpad_home_gesture_guidance" msgid="3043931356096731966">"Ukuze uye esikrinini sakho sasekhaya nganoma isiphi isikhathi, swayipha uye phezulu ngeminwe emithathu usuka phansi esikrinini sakho."</string>
<string name="touchpad_home_gesture_success_title" msgid="3778407003948209795">"Kuhle!"</string>
<string name="touchpad_home_gesture_success_body" msgid="2404031094918807067">"Ukuqedile ukuthinta kokuya ekhaya."</string>
+ <!-- no translation found for touchpad_recent_apps_gesture_action_title (934906836867137906) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_guidance (6012057247259983871) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_title (8481920554139332593) -->
+ <skip />
+ <!-- no translation found for touchpad_recent_apps_gesture_success_body (4334263906697493273) -->
+ <skip />
<string name="tutorial_action_key_title" msgid="2659466586996495447">"Inkinobho yokufinyelela"</string>
<string name="tutorial_action_key_guidance" msgid="5718948664616999196">"Ukuze ufinyelele ama-app wakho, cindezela inkinobho yokufinyelela kukhibhodi yakho."</string>
<string name="tutorial_action_key_success_title" msgid="466467860120112933">"Halala!"</string>
@@ -1434,22 +1446,19 @@
<string name="overview_edu_notification_content" msgid="3578204677648432500">"Swayiphela phezulu bese uyabamba usebenzisa iminwe emithathu. Thepha ukuze ufunde kabanzi ngokunyakazisa umzimba."</string>
<string name="all_apps_edu_notification_title" msgid="372262997265569063">"Sebenzisa ikhibhodi yakho ukubuka wonke ama-app"</string>
<string name="all_apps_edu_notification_content" msgid="3255070575694025585">"Cindezela inkinobho yokufinyelela noma kunini. Thepha ukuze ufunde kabanzi ngokunyakazisa umzimba."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_title" msgid="4369307638184799742">"Ukufiphala okwengeziwe manje sekuyingxenye yebha yokukhanya"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_description" msgid="7513137763024327538">"Manje ungenza isikrini sifiphale ngokwengeziwe ngokwehlisa izinga lokukhanya nakakhulu kusukela phezulu kwesikrini sakho.\n\nLokhu kusebenza kahle kakhulu uma usendaweni emnyama."</string>
- <string name="accessibility_deprecate_extra_dim_dialog_button" msgid="1782147201534669800">"Susa isinqamuleli esifiphele esengeziwe"</string>
- <string name="accessibility_deprecate_extra_dim_dialog_toast" msgid="4070696910424515757">"Isinqamuleli esifiphele ngokwengeziwe sikhishiwe. Ukuze wehlise ukukhanya kwakho, sebenzisa ibha yokukhanya evamile."</string>
- <!-- no translation found for qs_edit_mode_category_connectivity (4559726936546032672) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_title (910988771011857460) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_accessibility (7969091385071475922) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_description (4453123359258743230) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_utilities (8123080090108420095) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_button (3947537827396916005) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_privacy (6577774443194551775) -->
+ <!-- no translation found for accessibility_deprecate_extra_dim_dialog_toast (165474092660941104) -->
<skip />
- <!-- no translation found for qs_edit_mode_category_providedByApps (8346112074897919019) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_display (4749511439121053942) -->
- <skip />
- <!-- no translation found for qs_edit_mode_category_unknown (509314252124053550) -->
- <skip />
+ <string name="qs_edit_mode_category_connectivity" msgid="4559726936546032672">"Ukuxhumana"</string>
+ <string name="qs_edit_mode_category_accessibility" msgid="7969091385071475922">"Ukufinyeleleka"</string>
+ <string name="qs_edit_mode_category_utilities" msgid="8123080090108420095">"Okusetshenziswayo"</string>
+ <string name="qs_edit_mode_category_privacy" msgid="6577774443194551775">"Ubumfihlo"</string>
+ <string name="qs_edit_mode_category_providedByApps" msgid="8346112074897919019">"Kuhlinzekwe ama-app"</string>
+ <string name="qs_edit_mode_category_display" msgid="4749511439121053942">"Bonisa"</string>
+ <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Akwaziwa"</string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e94248d..00846cb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1005,6 +1005,10 @@
<dimen name="ksh_app_item_minimum_height">64dp</dimen>
<dimen name="ksh_category_separator_margin">16dp</dimen>
+ <!-- New keyboard shortcut helper -->
+ <dimen name="shortcut_helper_width">412dp</dimen>
+ <dimen name="shortcut_helper_height">728dp</dimen>
+
<!-- The size of corner radius of the arrow in the onboarding toast. -->
<dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f9c2aef..ba3822b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3114,6 +3114,10 @@
<string name="media_output_group_title_speakers_and_displays">Speakers & Displays</string>
<!-- Title for Suggested Devices group. [CHAR LIMIT=NONE] -->
<string name="media_output_group_title_suggested_device">Suggested Devices</string>
+ <!-- Title for input device group. [CHAR LIMIT=NONE] -->
+ <string name="media_input_group_title">Input</string>
+ <!-- Title for output device group. [CHAR LIMIT=NONE] -->
+ <string name="media_output_group_title">Output</string>
<!-- Summary for end session dialog. [CHAR LIMIT=NONE] -->
<string name="media_output_end_session_dialog_summary">Stop your shared session to move media to another device</string>
<!-- Button text for stopping session [CHAR LIMIT=60] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
index a5b62b6..b16c683 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardConstants.java
@@ -28,5 +28,4 @@
* be used temporarily for debugging.
*/
public static final boolean DEBUG = Log.isLoggable("Keyguard", Log.DEBUG);
- public static final boolean DEBUG_SIM_STATES = true;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 7efe2dd..ffbc85c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -968,6 +968,15 @@
constraintSet.constrainWidth(mViewFlipper.getId(), MATCH_CONSTRAINT);
constraintSet.applyTo(mView);
}
+
+ @Override
+ public void onDestroy() {
+ if (mView == null) return;
+ ConstraintSet constraintSet = new ConstraintSet();
+ constraintSet.clone(mView);
+ constraintSet.clear(mViewFlipper.getId());
+ constraintSet.applyTo(mView);
+ }
}
/**
@@ -1043,12 +1052,20 @@
@Override
public void onDensityOrFontScaleChanged() {
mView.removeView(mUserSwitcherViewGroup);
+ mView.removeView(mUserSwitcher);
inflateUserSwitcher();
}
@Override
public void onDestroy() {
- mUserSwitcherController.removeUserSwitchCallback(mUserSwitchCallback);
+ ConstraintSet constraintSet = new ConstraintSet();
+ constraintSet.clone(mView);
+ constraintSet.clear(mUserSwitcherViewGroup.getId());
+ constraintSet.clear(mViewFlipper.getId());
+ constraintSet.applyTo(mView);
+
+ mView.removeView(mUserSwitcherViewGroup);
+ mView.removeView(mUserSwitcher);
}
private Drawable findLargeUserIcon(int userId) {
@@ -1344,5 +1361,13 @@
constraintSet.constrainPercentWidth(mViewFlipper.getId(), 0.5f);
constraintSet.applyTo(mView);
}
+
+ @Override
+ public void onDestroy() {
+ ConstraintSet constraintSet = new ConstraintSet();
+ constraintSet.clone(mView);
+ constraintSet.clear(mViewFlipper.getId());
+ constraintSet.applyTo(mView);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 1c1acf8..52c93f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -53,7 +53,6 @@
extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
public static final String TAG = "KeyguardSimPinView";
private static final String LOG_TAG = "KeyguardSimPinView";
- private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final TelephonyManager mTelephonyManager;
@@ -71,7 +70,7 @@
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@Override
public void onSimStateChanged(int subId, int slotId, int simState) {
- if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+ Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
// If subId has gone to PUK required then we need to go to the PUK screen.
if (subId == mSubId && simState == TelephonyManager.SIM_STATE_PUK_REQUIRED) {
getKeyguardSecurityCallback().showCurrentSecurityScreen();
@@ -129,7 +128,7 @@
@Override
void resetState() {
super.resetState();
- if (DEBUG) Log.v(TAG, "Resetting state");
+ Log.v(TAG, "Resetting state");
handleSubInfoChangeIfNeeded();
mMessageAreaController.setMessage("");
if (mShowDefaultMessage) {
@@ -216,11 +215,9 @@
mMessageAreaController.setMessage(mView.getResources().getString(
R.string.kg_password_pin_failed));
}
- if (DEBUG) {
- Log.d(LOG_TAG, "verifyPasswordAndUnlock "
- + " CheckSimPin.onSimCheckResponse: " + result
- + " attemptsRemaining=" + result.getAttemptsRemaining());
- }
+ Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+ + " CheckSimPin.onSimCheckResponse: " + result
+ + " attemptsRemaining=" + result.getAttemptsRemaining());
}
getKeyguardSecurityCallback().userActivity();
mCheckSimPinThread = null;
@@ -280,10 +277,8 @@
displayMessage = mView.getResources()
.getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
}
- if (DEBUG) {
- Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining="
- + attemptsRemaining + " displayMessage=" + displayMessage);
- }
+ Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining="
+ + attemptsRemaining + " displayMessage=" + displayMessage);
return displayMessage;
}
@@ -323,14 +318,10 @@
@Override
public void run() {
- if (DEBUG) {
- Log.v(TAG, "call supplyIccLockPin(subid=" + mSubId + ")");
- }
+ Log.v(TAG, "call supplyIccLockPin(subid=" + mSubId + ")");
TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
final PinResult result = telephonyManager.supplyIccLockPin(mPin);
- if (DEBUG) {
- Log.v(TAG, "supplyIccLockPin returned: " + result.toString());
- }
+ Log.v(TAG, "supplyIccLockPin returned: " + result.toString());
mView.post(() -> onSimCheckResponse(result));
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f731186..22130f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -43,6 +43,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.systemui.Flags.simPinBouncerReset;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
import android.annotation.AnyThread;
@@ -1703,6 +1704,9 @@
intent.getStringExtra(Intent.EXTRA_SIM_STATE),
args.slotId,
args.subId);
+ if (args.slotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ return;
+ }
mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, args.subId, args.slotId, args.simState)
.sendToTarget();
} else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
@@ -1940,7 +1944,13 @@
}
int state = TelephonyManager.SIM_STATE_UNKNOWN;
String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE);
- int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
+
+ int defaultSlotId = 0;
+ if (simPinBouncerReset()) {
+ defaultSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ }
+ int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX,
+ defaultSlotId);
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) {
@@ -2479,6 +2489,12 @@
this::onTransitionStateChanged
);
}
+
+ // start() can be invoked in the middle of user switching, so check for this state and issue
+ // the call manually as that important event was missed.
+ if (mUserTracker.isUserSwitching()) {
+ handleUserSwitching(mUserTracker.getUserId(), () -> {});
+ }
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index c28bce2..6d6cd45 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -294,7 +294,9 @@
/** Tell the bouncer that bouncer is requested when device is already authenticated */
fun notifyUserRequestedBouncerWhenAlreadyAuthenticated(userId: Int) {
- applicationScope.launch { repository.setKeyguardAuthenticatedPrimaryAuth(userId) }
+ applicationScope.launch {
+ repository.setUserRequestedBouncerWhenAlreadyAuthenticated(userId)
+ }
}
/** Tell the bouncer that keyguard is authenticated with biometrics. */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
index 73a8810..c60f932 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerContainerViewModel.kt
@@ -17,12 +17,14 @@
package com.android.systemui.bouncer.ui.viewmodel
import androidx.compose.runtime.getValue
-import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.kotlin.Utils.Companion.sample
+import com.android.systemui.util.kotlin.sample
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.coroutineScope
@@ -34,7 +36,7 @@
private val legacyInteractor: PrimaryBouncerInteractor,
private val authenticationInteractor: AuthenticationInteractor,
private val selectedUserInteractor: SelectedUserInteractor,
- private val viewMediatorCallback: ViewMediatorCallback?,
+ private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
) : ExclusiveActivatable() {
private val hydrator = Hydrator("BouncerContainerViewModel")
@@ -45,6 +47,18 @@
override suspend fun onActivated(): Nothing {
coroutineScope {
launch {
+ legacyInteractor.isShowing
+ .sample(deviceUnlockedInteractor.deviceUnlockStatus, ::Pair)
+ .collect { (isShowing, unlockStatus) ->
+ if (isShowing && unlockStatus.isUnlocked) {
+ legacyInteractor.notifyUserRequestedBouncerWhenAlreadyAuthenticated(
+ selectedUserInteractor.getSelectedUserId()
+ )
+ }
+ }
+ }
+
+ launch {
authenticationInteractor.onAuthenticationResult.collect { authenticationSucceeded ->
if (authenticationSucceeded) {
legacyInteractor.notifyKeyguardAuthenticatedPrimaryAuth(
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index c7a47b1..1ada56d 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -30,6 +30,7 @@
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Build;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -37,6 +38,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.user.utils.UserScopedService;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -67,13 +69,13 @@
public ClipboardListener(Context context,
Provider<ClipboardOverlayController> clipboardOverlayControllerProvider,
ClipboardToast clipboardToast,
- ClipboardManager clipboardManager,
+ UserScopedService<ClipboardManager> clipboardManager,
KeyguardManager keyguardManager,
UiEventLogger uiEventLogger) {
mContext = context;
mOverlayProvider = clipboardOverlayControllerProvider;
mClipboardToast = clipboardToast;
- mClipboardManager = clipboardManager;
+ mClipboardManager = clipboardManager.forUser(UserHandle.CURRENT);
mKeyguardManager = keyguardManager;
mUiEventLogger = uiEventLogger;
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index b570e14..a687734 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -117,7 +117,7 @@
sceneInteractor: SceneInteractor,
@CommunalLog logBuffer: LogBuffer,
@CommunalTableLog tableLogBuffer: TableLogBuffer,
- private val managedProfileController: ManagedProfileController
+ private val managedProfileController: ManagedProfileController,
) {
private val logger = Logger(logBuffer, "CommunalInteractor")
@@ -154,7 +154,7 @@
allOf(
communalSettingsInteractor.isCommunalEnabled,
not(keyguardInteractor.isEncryptedOrLockdown),
- keyguardInteractor.isKeyguardShowing
+ keyguardInteractor.isKeyguardShowing,
)
.distinctUntilChanged()
.onEach { available ->
@@ -342,7 +342,7 @@
fun changeScene(
newScene: SceneKey,
loggingReason: String,
- transitionKey: TransitionKey? = null
+ transitionKey: TransitionKey? = null,
) = communalSceneInteractor.changeScene(newScene, loggingReason, transitionKey)
fun setEditModeOpen(isOpen: Boolean) {
@@ -354,9 +354,7 @@
}
/** Show the widget editor Activity. */
- fun showWidgetEditor(
- shouldOpenWidgetPickerOnStart: Boolean = false,
- ) {
+ fun showWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean = false) {
communalSceneInteractor.setEditModeState(EditModeState.STARTING)
editWidgetsActivityStarter.startActivity(shouldOpenWidgetPickerOnStart)
}
@@ -419,7 +417,7 @@
IntentFilter().apply {
addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
- },
+ }
)
.emitOnStart()
@@ -450,7 +448,7 @@
rank = widget.rank,
providerInfo = widget.providerInfo,
appWidgetHost = appWidgetHost,
- inQuietMode = isQuietModeEnabled(widget.providerInfo.profile)
+ inQuietMode = isQuietModeEnabled(widget.providerInfo.profile),
)
}
is CommunalWidgetContentModel.Pending -> {
@@ -468,7 +466,7 @@
/** Filter widgets based on whether their associated profile is allowed by device policy. */
private fun filterWidgetsAllowedByDevicePolicy(
list: List<CommunalWidgetContentModel>,
- disallowedByDevicePolicyUser: UserInfo?
+ disallowedByDevicePolicyUser: UserInfo?,
): List<CommunalWidgetContentModel> =
if (disallowedByDevicePolicyUser == null) {
list
@@ -507,7 +505,7 @@
* A flow of ongoing content, including smartspace timers and umo, ordered by creation time and
* sized dynamically.
*/
- val ongoingContent: Flow<List<CommunalContentModel.Ongoing>> =
+ fun ongoingContent(isMediaHostVisible: Boolean): Flow<List<CommunalContentModel.Ongoing>> =
combine(smartspaceRepository.timers, mediaRepository.mediaModel) { timers, media ->
val ongoingContent = mutableListOf<CommunalContentModel.Ongoing>()
@@ -523,22 +521,20 @@
)
// Add UMO
- if (media.hasAnyMediaOrRecommendation) {
+ if (isMediaHostVisible && media.hasAnyMediaOrRecommendation) {
ongoingContent.add(
CommunalContentModel.Umo(
- createdTimestampMillis = media.createdTimestampMillis,
+ createdTimestampMillis = media.createdTimestampMillis
)
)
}
- // Order by creation time descending
+ // Order by creation time descending.
ongoingContent.sortByDescending { it.createdTimestampMillis }
+ // Resize the items.
+ ongoingContent.resizeItems()
- // Dynamic sizing
- ongoingContent.forEachIndexed { index, model ->
- model.size = dynamicContentSize(ongoingContent.size, index)
- }
-
+ // Return the sorted and resized items.
ongoingContent
}
.flowOn(bgDispatcher)
@@ -548,7 +544,7 @@
* stale data following user deletion.
*/
private fun filterWidgetsByExistingUsers(
- list: List<CommunalWidgetContentModel>,
+ list: List<CommunalWidgetContentModel>
): List<CommunalWidgetContentModel> {
val currentUserIds = userTracker.userProfiles.map { it.id }.toSet()
return list.filter { widget ->
@@ -560,6 +556,40 @@
}
}
+ // Dynamically resizes the height of items in the list of ongoing items such that they fit in
+ // columns in as compact a space as possible.
+ //
+ // Currently there are three possible sizes. When the total number is 1, size for that content
+ // is [FULL], when the total number is 2, size for each is [HALF], and 3, size for each is
+ // [THIRD].
+ //
+ // This algorithm also respects each item's minimum size. All items in a column will have the
+ // same size, and all items in a column will be no smaller than any item's minimum size.
+ private fun List<CommunalContentModel.Ongoing>.resizeItems() {
+ fun resizeColumn(c: List<CommunalContentModel.Ongoing>) {
+ if (c.isEmpty()) return
+ val newSize = CommunalContentSize.toSize(span = FULL.span / c.size)
+ c.forEach { item -> item.size = newSize }
+ }
+
+ val column = mutableListOf<CommunalContentModel.Ongoing>()
+ var available = FULL.span
+
+ forEach { item ->
+ if (available < item.minSize.span) {
+ resizeColumn(column)
+ column.clear()
+ available = FULL.span
+ }
+
+ column.add(item)
+ available -= item.minSize.span
+ }
+
+ // Make sure to resize the final column.
+ resizeColumn(column)
+ }
+
companion object {
const val TAG = "CommunalInteractor"
@@ -574,31 +604,6 @@
* of -1 means that the user's chosen screen timeout will be used instead.
*/
const val AWAKE_INTERVAL_MS = -1
-
- /**
- * Calculates the content size dynamically based on the total number of contents of that
- * type.
- *
- * Contents with the same type are expected to fill each column evenly. Currently there are
- * three possible sizes. When the total number is 1, size for that content is [FULL], when
- * the total number is 2, size for each is [HALF], and 3, size for each is [THIRD].
- *
- * When dynamic contents fill in multiple columns, the first column follows the algorithm
- * above, and the remaining contents are packed in [THIRD]s. For example, when the total
- * number if 4, the first one is [FULL], filling the column, and the remaining 3 are
- * [THIRD].
- *
- * @param size The total number of contents of this type.
- * @param index The index of the current content of this type.
- */
- private fun dynamicContentSize(size: Int, index: Int): CommunalContentSize {
- val remainder = size % CommunalContentSize.entries.size
- return CommunalContentSize.toSize(
- span =
- FULL.span /
- if (index > remainder - 1) CommunalContentSize.entries.size else remainder
- )
- }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index 4c821d4..c2f6e85 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -34,12 +34,18 @@
/** Size to be rendered in the grid. */
val size: CommunalContentSize
+ /** The minimum size content can be resized to. */
+ val minSize: CommunalContentSize
+ get() = CommunalContentSize.HALF
+
/**
* A type of communal content is ongoing / live / ephemeral, and can be sized and ordered
* dynamically.
*/
sealed interface Ongoing : CommunalContentModel {
override var size: CommunalContentSize
+ override val minSize
+ get() = CommunalContentSize.THIRD
/** Timestamp in milliseconds of when the content was created. */
val createdTimestampMillis: Long
@@ -72,7 +78,7 @@
data class DisabledWidget(
override val appWidgetId: Int,
override val rank: Int,
- val providerInfo: AppWidgetProviderInfo
+ val providerInfo: AppWidgetProviderInfo,
) : WidgetContent {
override val key = KEY.disabledWidget(appWidgetId)
override val componentName: ComponentName = providerInfo.provider
@@ -109,10 +115,7 @@
override val size = CommunalContentSize.HALF
}
- class Tutorial(
- id: Int,
- override var size: CommunalContentSize,
- ) : CommunalContentModel {
+ class Tutorial(id: Int, override var size: CommunalContentSize) : CommunalContentModel {
override val key = KEY.tutorial(id)
}
@@ -128,6 +131,7 @@
class Umo(
override val createdTimestampMillis: Long,
override var size: CommunalContentSize = CommunalContentSize.HALF,
+ override var minSize: CommunalContentSize = CommunalContentSize.HALF,
) : Ongoing {
override val key = KEY.umo()
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index d69ba1b..53109ac 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -125,15 +125,9 @@
private var frozenCommunalContent: List<CommunalContentModel>? = null
private val ongoingContent =
- combine(
- isMediaHostVisible,
- communalInteractor.ongoingContent.onEach { mediaHost.updateViewVisibility() }
- ) { mediaVisible, ongoingContent ->
- if (mediaVisible) {
- ongoingContent
- } else {
- // Media is not visible, don't show UMO
- ongoingContent.filterNot { it is CommunalContentModel.Umo }
+ isMediaHostVisible.flatMapLatest { isMediaHostVisible ->
+ communalInteractor.ongoingContent(isMediaHostVisible).onEach {
+ mediaHost.updateViewVisibility()
}
}
@@ -148,8 +142,7 @@
ongoingContent,
communalInteractor.widgetContent,
communalInteractor.ctaTileContent,
- ) { ongoing, widgets, ctaTile,
- ->
+ ) { ongoing, widgets, ctaTile ->
ongoing + widgets + ctaTile
}
}
@@ -172,10 +165,10 @@
allOf(
keyguardTransitionInteractor.isFinishedIn(
scene = Scenes.Communal,
- stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB
+ stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB,
),
keyguardInteractor.isKeyguardOccluded,
- not(keyguardInteractor.isAbleToDream)
+ not(keyguardInteractor.isAbleToDream),
)
.distinctUntilChanged()
.onEach { logger.d("isCommunalContentFlowFrozen: $it") }
@@ -208,7 +201,7 @@
combine(
keyguardTransitionInteractor.isFinishedIn(
scene = Scenes.Communal,
- stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB
+ stateWithoutSceneContainer = KeyguardState.GLANCEABLE_HUB,
),
communalInteractor.isIdleOnCommunal,
shadeInteractor.isAnyFullyExpanded,
@@ -221,7 +214,7 @@
object : View.AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(
host: View,
- info: AccessibilityNodeInfo
+ info: AccessibilityNodeInfo,
) {
super.onInitializeAccessibilityNodeInfo(host, info)
// Hint user to long press in order to enter edit mode
@@ -230,7 +223,7 @@
AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id,
resources
.getString(R.string.accessibility_action_label_edit_widgets)
- .lowercase()
+ .lowercase(),
)
)
}
@@ -238,7 +231,7 @@
override fun performAccessibilityAction(
host: View,
action: Int,
- args: Bundle?
+ args: Bundle?,
): Boolean {
when (action) {
AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK.id -> {
@@ -271,9 +264,7 @@
}
}
- override fun onOpenWidgetEditor(
- shouldOpenWidgetPickerOnStart: Boolean,
- ) {
+ override fun onOpenWidgetEditor(shouldOpenWidgetPickerOnStart: Boolean) {
persistScrollPosition()
communalInteractor.showWidgetEditor(shouldOpenWidgetPickerOnStart)
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 8818c3a..8f913ff 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -733,9 +733,8 @@
}
@Provides
- @Singleton
- static ClipboardManager provideClipboardManager(Context context) {
- return context.getSystemService(ClipboardManager.class);
+ static UserScopedService<ClipboardManager> provideClipboardManager(Context context) {
+ return new UserScopedServiceImpl<>(context, ClipboardManager.class);
}
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
index 81ea2e7..62720a5 100644
--- a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
@@ -79,7 +79,7 @@
.combine(concurrentDisplaysInProgessFlow) { pendingDisplay, concurrentDisplaysInProgress
->
if (pendingDisplay == null) {
- hideDialog()
+ dismissDialog()
} else {
showDialog(pendingDisplay, concurrentDisplaysInProgress)
}
@@ -88,17 +88,17 @@
}
private fun showDialog(pendingDisplay: PendingDisplay, concurrentDisplaysInProgess: Boolean) {
- hideDialog()
+ dismissDialog()
dialog =
bottomSheetFactory
.createDialog(
onStartMirroringClickListener = {
scope.launch(bgDispatcher) { pendingDisplay.enable() }
- hideDialog()
+ dismissDialog()
},
onCancelMirroring = {
scope.launch(bgDispatcher) { pendingDisplay.ignore() }
- hideDialog()
+ dismissDialog()
},
navbarBottomInsetsProvider = { Utils.getNavbarInsets(context).bottom },
showConcurrentDisplayInfo = concurrentDisplaysInProgess
@@ -106,8 +106,8 @@
.apply { show() }
}
- private fun hideDialog() {
- dialog?.hide()
+ private fun dismissDialog() {
+ dialog?.dismiss()
dialog = null
}
diff --git a/packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt b/packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt
index 1daaa11..500c5b3 100644
--- a/packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/data/model/GestureEduModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.education.data.model
+import com.android.systemui.contextualeducation.GestureType
import java.time.Instant
/**
@@ -23,6 +24,7 @@
* gesture stores its own model separately.
*/
data class GestureEduModel(
+ val gestureType: GestureType,
val signalCount: Int = 0,
val educationShownCount: Int = 0,
val lastShortcutTriggeredTime: Instant? = null,
diff --git a/packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt b/packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt
index 01f838f..2978595 100644
--- a/packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/data/repository/UserContextualEducationRepository.kt
@@ -17,6 +17,8 @@
package com.android.systemui.education.data.repository
import android.content.Context
+import android.hardware.input.InputManager
+import android.hardware.input.KeyGestureEvent
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.MutablePreferences
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
@@ -25,23 +27,31 @@
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.preferencesDataStoreFile
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.contextualeducation.GestureType.ALL_APPS
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.education.dagger.ContextualEducationModule.EduDataStoreScope
import com.android.systemui.education.data.model.EduDeviceConnectionTime
import com.android.systemui.education.data.model.GestureEduModel
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import java.time.Instant
+import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Provider
import kotlin.properties.Delegates.notNull
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
/**
@@ -64,6 +74,8 @@
suspend fun updateEduDeviceConnectionTime(
transform: (EduDeviceConnectionTime) -> EduDeviceConnectionTime
)
+
+ val keyboardShortcutTriggered: Flow<GestureType>
}
/**
@@ -75,9 +87,13 @@
@Inject
constructor(
@Application private val applicationContext: Context,
- @EduDataStoreScope private val dataStoreScopeProvider: Provider<CoroutineScope>
+ @EduDataStoreScope private val dataStoreScopeProvider: Provider<CoroutineScope>,
+ private val inputManager: InputManager,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
) : ContextualEducationRepository {
companion object {
+ const val TAG = "UserContextualEducationRepository"
+
const val SIGNAL_COUNT_SUFFIX = "_SIGNAL_COUNT"
const val NUMBER_OF_EDU_SHOWN_SUFFIX = "_NUMBER_OF_EDU_SHOWN"
const val LAST_SHORTCUT_TRIGGERED_TIME_SUFFIX = "_LAST_SHORTCUT_TRIGGERED_TIME"
@@ -98,6 +114,30 @@
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
private val prefData: Flow<Preferences> = datastore.filterNotNull().flatMapLatest { it.data }
+ override val keyboardShortcutTriggered: Flow<GestureType> =
+ conflatedCallbackFlow {
+ val listener =
+ InputManager.KeyGestureEventListener { event ->
+ // Only store keyboard shortcut time for gestures providing keyboard
+ // education
+ val shortcutType =
+ when (event.keyGestureType) {
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS -> ALL_APPS
+
+ else -> null
+ }
+
+ if (shortcutType != null) {
+ trySendWithFailureLogging(shortcutType, TAG)
+ }
+ }
+
+ inputManager.registerKeyGestureEventListener(Executor(Runnable::run), listener)
+ awaitClose { inputManager.unregisterKeyGestureEventListener(listener) }
+ }
+ .flowOn(backgroundDispatcher)
+
override fun setUser(userId: Int) {
dataStoreScope?.cancel()
val newDsScope = dataStoreScopeProvider.get()
@@ -136,7 +176,8 @@
preferences[getLastEducationTimeKey(gestureType)]?.let {
Instant.ofEpochSecond(it)
},
- userId = userId
+ userId = userId,
+ gestureType = gestureType,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/ContextualEducationInteractor.kt b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/ContextualEducationInteractor.kt
index 10be26e..c88b364 100644
--- a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/ContextualEducationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/ContextualEducationInteractor.kt
@@ -18,7 +18,10 @@
import com.android.systemui.CoreStartable
import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.contextualeducation.GestureType.ALL_APPS
import com.android.systemui.contextualeducation.GestureType.BACK
+import com.android.systemui.contextualeducation.GestureType.HOME
+import com.android.systemui.contextualeducation.GestureType.OVERVIEW
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.education.dagger.ContextualEducationModule.EduClock
@@ -53,6 +56,13 @@
) : CoreStartable {
val backGestureModelFlow = readEduModelsOnSignalCountChanged(BACK)
+ val homeGestureModelFlow = readEduModelsOnSignalCountChanged(HOME)
+ val overviewGestureModelFlow = readEduModelsOnSignalCountChanged(OVERVIEW)
+ val allAppsGestureModelFlow = readEduModelsOnSignalCountChanged(ALL_APPS)
+ val eduDeviceConnectionTimeFlow =
+ repository.readEduDeviceConnectionTime().distinctUntilChanged()
+
+ val keyboardShortcutTriggered = repository.keyboardShortcutTriggered
override fun start() {
backgroundScope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt
index 43855d9..faee326 100644
--- a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt
@@ -16,15 +16,8 @@
package com.android.systemui.education.domain.interactor
-import android.hardware.input.InputManager
-import android.hardware.input.InputManager.KeyGestureEventListener
-import android.hardware.input.KeyGestureEvent
import android.os.SystemProperties
import com.android.systemui.CoreStartable
-import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.contextualeducation.GestureType
-import com.android.systemui.contextualeducation.GestureType.ALL_APPS
-import com.android.systemui.contextualeducation.GestureType.BACK
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.education.dagger.ContextualEducationModule.EduClock
@@ -32,19 +25,19 @@
import com.android.systemui.education.shared.model.EducationInfo
import com.android.systemui.education.shared.model.EducationUiType
import com.android.systemui.inputdevice.data.repository.UserInputDeviceRepository
-import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import java.time.Clock
-import java.util.concurrent.Executor
import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
import kotlin.time.DurationUnit
import kotlin.time.toDuration
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.launch
/** Allow listening to new contextual education triggered */
@@ -55,7 +48,6 @@
@Background private val backgroundScope: CoroutineScope,
private val contextualEducationInteractor: ContextualEducationInteractor,
private val userInputDeviceRepository: UserInputDeviceRepository,
- private val inputManager: InputManager,
@EduClock private val clock: Clock,
) : CoreStartable {
@@ -82,34 +74,32 @@
private val _educationTriggered = MutableStateFlow<EducationInfo?>(null)
val educationTriggered = _educationTriggered.asStateFlow()
- private val keyboardShortcutTriggered: Flow<GestureType> = conflatedCallbackFlow {
- val listener = KeyGestureEventListener { event ->
- // Only store keyboard shortcut time for gestures providing keyboard education
- val shortcutType =
- when (event.keyGestureType) {
- KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS -> ALL_APPS
- else -> null
- }
-
- if (shortcutType != null) {
- trySendWithFailureLogging(shortcutType, TAG)
- }
- }
-
- inputManager.registerKeyGestureEventListener(Executor(Runnable::run), listener)
- awaitClose { inputManager.unregisterKeyGestureEventListener(listener) }
- }
-
+ @OptIn(ExperimentalCoroutinesApi::class)
override fun start() {
backgroundScope.launch {
- contextualEducationInteractor.backGestureModelFlow.collect {
- if (isUsageSessionExpired(it)) {
- contextualEducationInteractor.startNewUsageSession(BACK)
- } else if (isEducationNeeded(it)) {
- _educationTriggered.value = EducationInfo(BACK, getEduType(it), it.userId)
- contextualEducationInteractor.updateOnEduTriggered(BACK)
+ contextualEducationInteractor.eduDeviceConnectionTimeFlow
+ .flatMapLatest {
+ val gestureFlows = mutableListOf<Flow<GestureEduModel>>()
+ if (it.touchpadFirstConnectionTime != null) {
+ gestureFlows.add(contextualEducationInteractor.backGestureModelFlow)
+ gestureFlows.add(contextualEducationInteractor.homeGestureModelFlow)
+ gestureFlows.add(contextualEducationInteractor.overviewGestureModelFlow)
+ }
+
+ if (it.keyboardFirstConnectionTime != null) {
+ gestureFlows.add(contextualEducationInteractor.allAppsGestureModelFlow)
+ }
+ gestureFlows.merge()
}
- }
+ .collect {
+ if (isUsageSessionExpired(it)) {
+ contextualEducationInteractor.startNewUsageSession(it.gestureType)
+ } else if (isEducationNeeded(it)) {
+ _educationTriggered.value =
+ EducationInfo(it.gestureType, getEduType(it), it.userId)
+ contextualEducationInteractor.updateOnEduTriggered(it.gestureType)
+ }
+ }
}
backgroundScope.launch {
@@ -139,7 +129,7 @@
}
backgroundScope.launch {
- keyboardShortcutTriggered.collect {
+ contextualEducationInteractor.keyboardShortcutTriggered.collect {
contextualEducationInteractor.updateShortcutTriggerTime(it)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 6318dc0..0b775ab 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -31,9 +31,7 @@
import com.android.systemui.Flags.statusBarScreenSharingChips
import com.android.systemui.Flags.statusBarUseReposForCallChip
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.MigrateClocksToBlueprint
-import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.statusbar.notification.collection.SortBySectionTimeFlag
@@ -62,10 +60,6 @@
// SceneContainer dependencies
SceneContainerFlag.getFlagDependencies().forEach { (alpha, beta) -> alpha dependsOn beta }
- // ComposeLockscreen dependencies
- ComposeLockscreen.token dependsOn KeyguardBottomAreaRefactor.token
- ComposeLockscreen.token dependsOn MigrateClocksToBlueprint.token
-
// CommunalHub dependencies
communalHub dependsOn MigrateClocksToBlueprint.token
@@ -99,7 +93,7 @@
get() =
FlagToken(
FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON,
- statusBarCallChipNotificationIcon()
+ statusBarCallChipNotificationIcon(),
)
private inline val statusBarScreenSharingChipsToken
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
index e50c05c..8966209 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt
@@ -29,6 +29,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.QSLog
+import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -50,6 +51,7 @@
constructor(
private val vibratorHelper: VibratorHelper?,
private val keyguardStateController: KeyguardStateController,
+ private val falsingManager: FalsingManager,
@QSLog private val logBuffer: LogBuffer,
) {
@@ -72,7 +74,7 @@
private val durations =
vibratorHelper?.getPrimitiveDurations(
VibrationEffect.Composition.PRIMITIVE_LOW_TICK,
- VibrationEffect.Composition.PRIMITIVE_SPIN
+ VibrationEffect.Composition.PRIMITIVE_SPIN,
)
private var longPressHint: VibrationEffect? = null
@@ -152,15 +154,27 @@
logEvent(qsTile?.tileSpec, state, "animation completed")
when (state) {
State.RUNNING_FORWARD -> {
- vibrate(snapEffect)
- if (keyguardStateController.isUnlocked) {
- setState(State.LONG_CLICKED)
- } else {
+ val wasFalseLongTap = falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)
+ if (wasFalseLongTap) {
callback?.onResetProperties()
setState(State.IDLE)
+ logEvent(qsTile?.tileSpec, state, "false long click. No action triggered")
+ } else if (keyguardStateController.isUnlocked) {
+ vibrate(snapEffect)
+ setState(State.LONG_CLICKED)
+ qsTile?.longClick(expandable)
+ logEvent(qsTile?.tileSpec, state, "long click action triggered")
+ } else {
+ vibrate(snapEffect)
+ callback?.onResetProperties()
+ setState(State.IDLE)
+ qsTile?.longClick(expandable)
+ logEvent(
+ qsTile?.tileSpec,
+ state,
+ "properties reset and long click action triggered",
+ )
}
- logEvent(qsTile?.tileSpec, state, "long click action triggered")
- qsTile?.longClick(expandable)
}
State.RUNNING_BACKWARDS_FROM_UP -> {
callback?.onEffectFinishedReversing()
@@ -236,7 +250,7 @@
LongPressHapticBuilder.createLongPressHint(
durations?.get(0) ?: LongPressHapticBuilder.INVALID_DURATION,
durations?.get(1) ?: LongPressHapticBuilder.INVALID_DURATION,
- effectDuration
+ effectDuration,
)
setState(State.IDLE)
return true
@@ -265,7 +279,7 @@
}
override fun dialogTransitionController(
- cuj: DialogCuj?,
+ cuj: DialogCuj?
): DialogTransitionAnimator.Controller? =
DialogTransitionAnimator.Controller.fromView(view, cuj)
}
@@ -298,7 +312,7 @@
str2 = event
str3 = state.name
},
- { "[long-press effect on $str1 tile] $str2 on state: $str3" }
+ { "[long-press effect on $str1 tile] $str2 on state: $str3" },
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index beec348..4bf552e0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -144,7 +144,7 @@
useSinglePane,
onSearchQueryChanged,
modifier,
- onKeyboardSettingsClicked
+ onKeyboardSettingsClicked,
)
}
else -> {
@@ -159,7 +159,7 @@
useSinglePane: @Composable () -> Boolean,
onSearchQueryChanged: (String) -> Unit,
modifier: Modifier,
- onKeyboardSettingsClicked: () -> Unit
+ onKeyboardSettingsClicked: () -> Unit,
) {
var selectedCategoryType by
remember(shortcutsUiState.defaultSelectedCategory) {
@@ -183,7 +183,7 @@
shortcutsUiState.shortcutCategories,
selectedCategoryType,
onCategorySelected = { selectedCategoryType = it },
- onKeyboardSettingsClicked
+ onKeyboardSettingsClicked,
)
}
}
@@ -223,14 +223,14 @@
searchQuery,
categories,
selectedCategoryType,
- onCategorySelected
+ onCategorySelected,
)
Spacer(modifier = Modifier.weight(1f))
}
KeyboardSettings(
horizontalPadding = 16.dp,
verticalPadding = 32.dp,
- onClick = onKeyboardSettingsClicked
+ onClick = onKeyboardSettingsClicked,
)
}
}
@@ -282,15 +282,11 @@
onClick: () -> Unit,
shape: Shape,
) {
- Surface(
- color = MaterialTheme.colorScheme.surfaceBright,
- shape = shape,
- onClick = onClick,
- ) {
+ Surface(color = MaterialTheme.colorScheme.surfaceBright, shape = shape, onClick = onClick) {
Column {
Row(
verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier.fillMaxWidth().heightIn(min = 88.dp).padding(horizontal = 16.dp)
+ modifier = Modifier.fillMaxWidth().heightIn(min = 88.dp).padding(horizontal = 16.dp),
) {
ShortcutCategoryIcon(modifier = Modifier.size(24.dp), source = category.icon)
Spacer(modifier = Modifier.width(16.dp))
@@ -327,7 +323,7 @@
source: IconSource,
modifier: Modifier = Modifier,
contentDescription: String? = null,
- tint: Color = LocalContentColor.current
+ tint: Color = LocalContentColor.current,
) {
if (source.imageVector != null) {
Icon(source.imageVector, contentDescription, modifier, tint)
@@ -350,7 +346,7 @@
private fun getApplicationLabelForCurrentApp(
type: ShortcutCategoryType.CurrentApp,
- context: Context
+ context: Context,
): String {
val packageManagerForUser = CentralSurfaces.getPackageManagerForUser(context, context.userId)
return try {
@@ -358,7 +354,7 @@
packageManagerForUser.getApplicationInfoAsUser(
type.packageName,
/* flags = */ 0,
- context.userId
+ context.userId,
)
packageManagerForUser.getApplicationLabel(currentAppInfo).toString()
} catch (e: NameNotFoundException) {
@@ -377,13 +373,13 @@
} else {
0f
},
- label = "Expand icon rotation animation"
+ label = "Expand icon rotation animation",
)
Icon(
modifier =
Modifier.background(
color = MaterialTheme.colorScheme.surfaceContainerHigh,
- shape = CircleShape
+ shape = CircleShape,
)
.graphicsLayer { rotationZ = expandIconRotationDegrees },
imageVector = Icons.Default.ExpandMore,
@@ -393,7 +389,7 @@
} else {
stringResource(R.string.shortcut_helper_content_description_expand_icon)
},
- tint = MaterialTheme.colorScheme.onSurface
+ tint = MaterialTheme.colorScheme.onSurface,
)
}
@@ -435,11 +431,11 @@
Row(Modifier.fillMaxWidth()) {
StartSidePanel(
onSearchQueryChanged = onSearchQueryChanged,
- modifier = Modifier.width(200.dp),
+ modifier = Modifier.width(240.dp),
categories = categories,
onKeyboardSettingsClicked = onKeyboardSettingsClicked,
selectedCategory = selectedCategoryType,
- onCategoryClicked = { onCategorySelected(it.type) }
+ onCategoryClicked = { onCategorySelected(it.type) },
)
Spacer(modifier = Modifier.width(24.dp))
EndSidePanel(searchQuery, Modifier.fillMaxSize().padding(top = 8.dp), selectedCategory)
@@ -475,7 +471,7 @@
modifier
.padding(vertical = 8.dp)
.background(MaterialTheme.colorScheme.surfaceBright, RoundedCornerShape(28.dp))
- .padding(horizontal = horizontalPadding, vertical = 24.dp)
+ .padding(horizontal = horizontalPadding, vertical = 24.dp),
)
}
@@ -484,7 +480,7 @@
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(28.dp),
- color = MaterialTheme.colorScheme.surfaceBright
+ color = MaterialTheme.colorScheme.surfaceBright,
) {
Column(Modifier.padding(24.dp)) {
SubCategoryTitle(subCategory.label)
@@ -519,7 +515,7 @@
isFocused = isFocused,
focusColor = MaterialTheme.colorScheme.secondary,
padding = 8.dp,
- cornerRadius = 16.dp
+ cornerRadius = 16.dp,
)
) {
Row(
@@ -528,21 +524,12 @@
verticalAlignment = Alignment.CenterVertically,
) {
if (shortcut.icon != null) {
- ShortcutIcon(
- shortcut.icon,
- modifier = Modifier.size(24.dp),
- )
+ ShortcutIcon(shortcut.icon, modifier = Modifier.size(24.dp))
}
- ShortcutDescriptionText(
- searchQuery = searchQuery,
- shortcut = shortcut,
- )
+ ShortcutDescriptionText(searchQuery = searchQuery, shortcut = shortcut)
}
Spacer(modifier = Modifier.width(16.dp))
- ShortcutKeyCombinations(
- modifier = Modifier.weight(1f),
- shortcut = shortcut,
- )
+ ShortcutKeyCombinations(modifier = Modifier.weight(1f), shortcut = shortcut)
}
}
@@ -566,14 +553,11 @@
@OptIn(ExperimentalLayoutApi::class)
@Composable
-private fun ShortcutKeyCombinations(
- modifier: Modifier = Modifier,
- shortcut: Shortcut,
-) {
+private fun ShortcutKeyCombinations(modifier: Modifier = Modifier, shortcut: Shortcut) {
FlowRow(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(8.dp),
- horizontalArrangement = Arrangement.End
+ horizontalArrangement = Arrangement.End,
) {
shortcut.commands.forEachIndexed { index, command ->
if (index > 0) {
@@ -609,8 +593,8 @@
Modifier.height(36.dp)
.background(
color = MaterialTheme.colorScheme.surfaceContainer,
- shape = RoundedCornerShape(12.dp)
- ),
+ shape = RoundedCornerShape(12.dp),
+ )
) {
shortcutKeyContent()
}
@@ -630,7 +614,7 @@
Icon(
painter = painterResource(key.drawableResId),
contentDescription = null,
- modifier = Modifier.align(Alignment.Center).padding(6.dp)
+ modifier = Modifier.align(Alignment.Center).padding(6.dp),
)
}
@@ -701,7 +685,7 @@
KeyboardSettings(
horizontalPadding = 24.dp,
verticalPadding = 24.dp,
- onKeyboardSettingsClicked
+ onKeyboardSettingsClicked,
)
}
}
@@ -710,7 +694,7 @@
private fun CategoriesPanelTwoPane(
categories: List<ShortcutCategory>,
selectedCategory: ShortcutCategoryType?,
- onCategoryClicked: (ShortcutCategory) -> Unit
+ onCategoryClicked: (ShortcutCategory) -> Unit,
) {
Column {
categories.fastForEach {
@@ -718,7 +702,7 @@
label = it.label(LocalContext.current),
iconSource = it.icon,
selected = selectedCategory == it.type,
- onClick = { onCategoryClicked(it) }
+ onClick = { onCategoryClicked(it) },
)
}
}
@@ -733,32 +717,31 @@
colors: NavigationDrawerItemColors =
NavigationDrawerItemDefaults.colors(unselectedContainerColor = Color.Transparent),
) {
- val interactionSource = remember { MutableInteractionSource() }
- val isFocused by interactionSource.collectIsFocusedAsState()
-
SelectableShortcutSurface(
selected = selected,
onClick = onClick,
- modifier =
- Modifier.semantics { role = Role.Tab }
- .heightIn(min = 64.dp)
- .fillMaxWidth()
- .outlineFocusModifier(
- isFocused = isFocused,
- focusColor = MaterialTheme.colorScheme.secondary,
- padding = 2.dp,
- cornerRadius = 33.dp
- ),
+ modifier = Modifier.semantics { role = Role.Tab }.heightIn(min = 64.dp).fillMaxWidth(),
shape = RoundedCornerShape(28.dp),
color = colors.containerColor(selected).value,
- interactionSource = interactionSource
+ interactionsConfig =
+ InteractionsConfig(
+ hoverOverlayColor = MaterialTheme.colorScheme.onSurface,
+ hoverOverlayAlpha = 0.11f,
+ pressedOverlayColor = MaterialTheme.colorScheme.onSurface,
+ pressedOverlayAlpha = 0.15f,
+ focusOutlineColor = MaterialTheme.colorScheme.secondary,
+ focusOutlineStrokeWidth = 3.dp,
+ focusOutlinePadding = 2.dp,
+ surfaceCornerRadius = 28.dp,
+ focusOutlineCornerRadius = 33.dp,
+ ),
) {
Row(Modifier.padding(horizontal = 24.dp), verticalAlignment = Alignment.CenterVertically) {
ShortcutCategoryIcon(
modifier = Modifier.size(24.dp),
source = iconSource,
contentDescription = null,
- tint = colors.iconColor(selected).value
+ tint = colors.iconColor(selected).value,
)
Spacer(Modifier.width(12.dp))
Box(Modifier.weight(1f)) {
@@ -766,7 +749,7 @@
fontSize = 18.sp,
color = colors.textColor(selected).value,
style = MaterialTheme.typography.headlineSmall,
- text = label
+ text = label,
)
}
}
@@ -777,7 +760,7 @@
isFocused: Boolean,
focusColor: Color,
padding: Dp,
- cornerRadius: Dp
+ cornerRadius: Dp,
): Modifier {
if (isFocused) {
return this.drawWithContent {
@@ -795,7 +778,7 @@
style = Stroke(width = 3.dp.toPx()),
topLeft = focusOutline.topLeft,
size = focusOutline.size,
- cornerRadius = CornerRadius(cornerRadius.toPx())
+ cornerRadius = CornerRadius(cornerRadius.toPx()),
)
}
// Increasing Z-Index so focus outline is drawn on top of "selected" category
@@ -815,9 +798,9 @@
Text(
text = stringResource(R.string.shortcut_helper_title),
color = MaterialTheme.colorScheme.onSurface,
- style = MaterialTheme.typography.headlineSmall
+ style = MaterialTheme.typography.headlineSmall,
)
- }
+ },
)
}
@@ -852,43 +835,48 @@
onSearch = {},
leadingIcon = { Icon(Icons.Default.Search, contentDescription = null) },
placeholder = { Text(text = stringResource(R.string.shortcut_helper_search_placeholder)) },
- content = {}
+ content = {},
)
}
@Composable
private fun KeyboardSettings(horizontalPadding: Dp, verticalPadding: Dp, onClick: () -> Unit) {
val interactionSource = remember { MutableInteractionSource() }
- val isFocused by interactionSource.collectIsFocusedAsState()
ClickableShortcutSurface(
onClick = onClick,
shape = RoundedCornerShape(24.dp),
color = Color.Transparent,
- modifier = Modifier.semantics { role = Role.Button }.fillMaxWidth(),
- interactionSource = interactionSource
+ modifier =
+ Modifier.semantics { role = Role.Button }
+ .fillMaxWidth()
+ .padding(horizontal = 12.dp),
+ interactionSource = interactionSource,
+ interactionsConfig =
+ InteractionsConfig(
+ hoverOverlayColor = MaterialTheme.colorScheme.onSurface,
+ hoverOverlayAlpha = 0.11f,
+ pressedOverlayColor = MaterialTheme.colorScheme.onSurface,
+ pressedOverlayAlpha = 0.15f,
+ focusOutlineColor = MaterialTheme.colorScheme.secondary,
+ focusOutlinePadding = 8.dp,
+ focusOutlineStrokeWidth = 3.dp,
+ surfaceCornerRadius = 24.dp,
+ focusOutlineCornerRadius = 28.dp,
+ hoverPadding = 8.dp,
+ ),
) {
- Row(
- modifier =
- Modifier.padding(horizontal = 12.dp, vertical = 16.dp)
- .outlineFocusModifier(
- isFocused = isFocused,
- focusColor = MaterialTheme.colorScheme.secondary,
- padding = 8.dp,
- cornerRadius = 28.dp
- ),
- verticalAlignment = Alignment.CenterVertically
- ) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
Text(
"Keyboard Settings",
color = MaterialTheme.colorScheme.onSurfaceVariant,
- fontSize = 16.sp
+ fontSize = 16.sp,
)
Spacer(modifier = Modifier.weight(1f))
Icon(
imageVector = Icons.AutoMirrored.Default.OpenInNew,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier.size(24.dp)
+ modifier = Modifier.size(24.dp),
)
}
}
@@ -900,17 +888,15 @@
val singlePaneFirstCategory =
RoundedCornerShape(
topStart = Dimensions.SinglePaneCategoryCornerRadius,
- topEnd = Dimensions.SinglePaneCategoryCornerRadius
+ topEnd = Dimensions.SinglePaneCategoryCornerRadius,
)
val singlePaneLastCategory =
RoundedCornerShape(
bottomStart = Dimensions.SinglePaneCategoryCornerRadius,
- bottomEnd = Dimensions.SinglePaneCategoryCornerRadius
+ bottomEnd = Dimensions.SinglePaneCategoryCornerRadius,
)
val singlePaneSingleCategory =
- RoundedCornerShape(
- size = Dimensions.SinglePaneCategoryCornerRadius,
- )
+ RoundedCornerShape(size = Dimensions.SinglePaneCategoryCornerRadius)
val singlePaneCategory = RectangleShape
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
index 3ba3bd8..e49ce60 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
@@ -17,10 +17,16 @@
package com.android.systemui.keyboard.shortcut.ui.composable
import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.IndicationNodeFactory
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.FocusInteraction
+import androidx.compose.foundation.interaction.HoverInteraction
+import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
+import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.selection.selectable
import androidx.compose.material3.ColorScheme
@@ -35,17 +41,27 @@
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.NonRestartableComposable
import androidx.compose.runtime.Stable
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.drawscope.ContentDrawScope
+import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.node.DelegatableNode
+import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.zIndex
import com.android.compose.modifiers.thenIf
+import kotlinx.coroutines.launch
/**
* A selectable surface with no default focus/hover indications.
@@ -67,15 +83,17 @@
shadowElevation: Dp = 0.dp,
border: BorderStroke? = null,
interactionSource: MutableInteractionSource? = null,
- content: @Composable () -> Unit
+ interactionsConfig: InteractionsConfig = InteractionsConfig(),
+ content: @Composable () -> Unit,
) {
@Suppress("NAME_SHADOWING")
val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
CompositionLocalProvider(
LocalContentColor provides contentColor,
- LocalAbsoluteTonalElevation provides absoluteElevation
+ LocalAbsoluteTonalElevation provides absoluteElevation,
) {
+ val isFocused = interactionSource.collectIsFocusedAsState()
Box(
modifier =
modifier
@@ -85,16 +103,18 @@
backgroundColor =
surfaceColorAtElevation(color = color, elevation = absoluteElevation),
border = border,
- shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() }
+ shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() },
)
.selectable(
selected = selected,
interactionSource = interactionSource,
- indication = null,
+ indication =
+ ShortcutHelperIndication(interactionSource, interactionsConfig),
enabled = enabled,
- onClick = onClick
- ),
- propagateMinConstraints = true
+ onClick = onClick,
+ )
+ .thenIf(isFocused.value) { Modifier.zIndex(1f) },
+ propagateMinConstraints = true,
) {
content()
}
@@ -120,14 +140,15 @@
shadowElevation: Dp = 0.dp,
border: BorderStroke? = null,
interactionSource: MutableInteractionSource? = null,
- content: @Composable () -> Unit
+ interactionsConfig: InteractionsConfig = InteractionsConfig(),
+ content: @Composable () -> Unit,
) {
@Suppress("NAME_SHADOWING")
val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
val absoluteElevation = LocalAbsoluteTonalElevation.current + tonalElevation
CompositionLocalProvider(
LocalContentColor provides contentColor,
- LocalAbsoluteTonalElevation provides absoluteElevation
+ LocalAbsoluteTonalElevation provides absoluteElevation,
) {
Box(
modifier =
@@ -138,15 +159,16 @@
backgroundColor =
surfaceColorAtElevation(color = color, elevation = absoluteElevation),
border = border,
- shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() }
+ shadowElevation = with(LocalDensity.current) { shadowElevation.toPx() },
)
.clickable(
interactionSource = interactionSource,
- indication = null,
+ indication =
+ ShortcutHelperIndication(interactionSource, interactionsConfig),
enabled = enabled,
- onClick = onClick
+ onClick = onClick,
),
- propagateMinConstraints = true
+ propagateMinConstraints = true,
) {
content()
}
@@ -195,5 +217,105 @@
}
.thenIf(border != null) { Modifier.border(border!!, shape) }
.background(color = backgroundColor, shape = shape)
- .clip(shape)
}
+
+private class ShortcutHelperInteractionsNode(
+ private val interactionSource: InteractionSource,
+ private val interactionsConfig: InteractionsConfig,
+) : Modifier.Node(), DrawModifierNode {
+
+ var isFocused = mutableStateOf(false)
+ var isHovered = mutableStateOf(false)
+ var isPressed = mutableStateOf(false)
+
+ override fun onAttach() {
+ coroutineScope.launch {
+ val hoverInteractions = mutableListOf<HoverInteraction.Enter>()
+ val focusInteractions = mutableListOf<FocusInteraction.Focus>()
+ val pressInteractions = mutableListOf<PressInteraction.Press>()
+
+ interactionSource.interactions.collect { interaction ->
+ when (interaction) {
+ is FocusInteraction.Focus -> focusInteractions.add(interaction)
+ is FocusInteraction.Unfocus -> focusInteractions.remove(interaction.focus)
+ is HoverInteraction.Enter -> hoverInteractions.add(interaction)
+ is HoverInteraction.Exit -> hoverInteractions.remove(interaction.enter)
+ is PressInteraction.Press -> pressInteractions.add(interaction)
+ is PressInteraction.Release -> pressInteractions.remove(interaction.press)
+ is PressInteraction.Cancel -> pressInteractions.add(interaction.press)
+ }
+ isHovered.value = hoverInteractions.isNotEmpty()
+ isPressed.value = pressInteractions.isNotEmpty()
+ isFocused.value = focusInteractions.isNotEmpty()
+ }
+ }
+ }
+
+ override fun ContentDrawScope.draw() {
+
+ fun getRectangleWithPadding(padding: Dp, size: Size): Rect {
+ return Rect(Offset.Zero, size).let {
+ if (interactionsConfig.focusOutlinePadding > 0.dp) {
+ it.inflate(padding.toPx())
+ } else {
+ it.deflate(padding.unaryMinus().toPx())
+ }
+ }
+ }
+
+ drawContent()
+ if (isHovered.value) {
+ val hoverRect = getRectangleWithPadding(interactionsConfig.pressedPadding, size)
+ drawRoundRect(
+ color = interactionsConfig.hoverOverlayColor,
+ alpha = interactionsConfig.hoverOverlayAlpha,
+ cornerRadius = CornerRadius(interactionsConfig.surfaceCornerRadius.toPx()),
+ topLeft = hoverRect.topLeft,
+ size = hoverRect.size,
+ )
+ }
+ if (isPressed.value) {
+ val pressedRect = getRectangleWithPadding(interactionsConfig.pressedPadding, size)
+ drawRoundRect(
+ color = interactionsConfig.pressedOverlayColor,
+ alpha = interactionsConfig.pressedOverlayAlpha,
+ cornerRadius = CornerRadius(interactionsConfig.surfaceCornerRadius.toPx()),
+ topLeft = pressedRect.topLeft,
+ size = pressedRect.size,
+ )
+ }
+ if (isFocused.value) {
+ val focusOutline = getRectangleWithPadding(interactionsConfig.focusOutlinePadding, size)
+ drawRoundRect(
+ color = interactionsConfig.focusOutlineColor,
+ style = Stroke(width = interactionsConfig.focusOutlineStrokeWidth.toPx()),
+ topLeft = focusOutline.topLeft,
+ size = focusOutline.size,
+ cornerRadius = CornerRadius(interactionsConfig.focusOutlineCornerRadius.toPx()),
+ )
+ }
+ }
+}
+
+data class ShortcutHelperIndication(
+ private val interactionSource: InteractionSource,
+ private val interactionsConfig: InteractionsConfig,
+) : IndicationNodeFactory {
+ override fun create(interactionSource: InteractionSource): DelegatableNode {
+ return ShortcutHelperInteractionsNode(interactionSource, interactionsConfig)
+ }
+}
+
+data class InteractionsConfig(
+ val hoverOverlayColor: Color = Color.Transparent,
+ val hoverOverlayAlpha: Float = 0.0f,
+ val pressedOverlayColor: Color = Color.Transparent,
+ val pressedOverlayAlpha: Float = 0.0f,
+ val focusOutlineColor: Color = Color.Transparent,
+ val focusOutlineStrokeWidth: Dp = 0.dp,
+ val focusOutlinePadding: Dp = 0.dp,
+ val surfaceCornerRadius: Dp = 0.dp,
+ val focusOutlineCornerRadius: Dp = 0.dp,
+ val hoverPadding: Dp = 0.dp,
+ val pressedPadding: Dp = hoverPadding,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
index 2039743..799999a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/view/ShortcutHelperActivity.kt
@@ -39,6 +39,7 @@
import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.dpToPx
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
@@ -51,10 +52,8 @@
*/
class ShortcutHelperActivity
@Inject
-constructor(
- private val userTracker: UserTracker,
- private val viewModel: ShortcutHelperViewModel,
-) : ComponentActivity() {
+constructor(private val userTracker: UserTracker, private val viewModel: ShortcutHelperViewModel) :
+ ComponentActivity() {
private val bottomSheetContainer
get() = requireViewById<View>(R.id.shortcut_helper_sheet_container)
@@ -69,7 +68,7 @@
setupEdgeToEdge()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_keyboard_shortcut_helper)
- setUpBottomSheetWidth()
+ setUpWidth()
expandBottomSheet()
setUpInsets()
setUpPredictiveBack()
@@ -80,6 +79,13 @@
viewModel.onViewOpened()
}
+ private fun setUpWidth() {
+ // we override this because when maxWidth isn't specified, material imposes a max width
+ // constraint on bottom sheets on larger screens which is smaller than our desired width.
+ bottomSheetBehavior.maxWidth =
+ resources.getDimension(R.dimen.shortcut_helper_width).dpToPx(resources).toInt()
+ }
+
private fun setUpComposeView() {
requireViewById<ComposeView>(R.id.shortcut_helper_compose_container).apply {
setContent {
@@ -102,7 +108,7 @@
try {
startActivityAsUser(
Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS),
- userTracker.userHandle
+ userTracker.userHandle,
)
} catch (e: ActivityNotFoundException) {
// From the Settings docs: In some cases, a matching Activity may not exist, so ensure
@@ -133,15 +139,6 @@
window.setDecorFitsSystemWindows(false)
}
- private fun setUpBottomSheetWidth() {
- val sheetScreenWidthFraction =
- resources.getFloat(R.dimen.shortcut_helper_screen_width_fraction)
- // maxWidth needs to be set before the sheet is drawn, otherwise the call will have no
- // effect.
- val screenWidth = windowManager.maximumWindowMetrics.bounds.width()
- bottomSheetBehavior.maxWidth = (sheetScreenWidthFraction * screenWidth).toInt()
- }
-
private fun setUpInsets() {
bottomSheetContainer.setOnApplyWindowInsetsListener { _, insets ->
val safeDrawingInsets = insets.safeDrawing
@@ -153,7 +150,7 @@
bottomSheet.updatePadding(
left = safeDrawingInsets.left,
right = safeDrawingInsets.right,
- bottom = safeDrawingInsets.bottom
+ bottom = safeDrawingInsets.bottom,
)
// The bottom sheet has to be expanded only after setting up insets, otherwise there is
// a bug and it will not use full height.
@@ -191,7 +188,7 @@
}
onBackPressedDispatcher.addCallback(
owner = this,
- onBackPressedCallback = onBackPressedCallback
+ onBackPressedCallback = onBackPressedCallback,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 342325f..6df8355 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -54,29 +54,25 @@
addURI(
Contract.AUTHORITY,
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME
),
MATCH_CODE_ALL_SLOTS,
)
addURI(
Contract.AUTHORITY,
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME
),
MATCH_CODE_ALL_AFFORDANCES,
)
addURI(
Contract.AUTHORITY,
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
),
MATCH_CODE_ALL_SELECTIONS,
)
- addURI(
- Contract.AUTHORITY,
- Contract.FlagsTable.TABLE_NAME,
- MATCH_CODE_ALL_FLAGS,
- )
+ addURI(Contract.AUTHORITY, Contract.FlagsTable.TABLE_NAME, MATCH_CODE_ALL_FLAGS)
}
override fun onCreate(): Boolean {
@@ -106,15 +102,15 @@
when (uriMatcher.match(uri)) {
MATCH_CODE_ALL_SLOTS ->
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.SlotTable.TABLE_NAME
)
MATCH_CODE_ALL_AFFORDANCES ->
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.AffordanceTable.TABLE_NAME
)
MATCH_CODE_ALL_SELECTIONS ->
Contract.LockScreenQuickAffordances.qualifiedTablePath(
- Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME,
+ Contract.LockScreenQuickAffordances.SelectionTable.TABLE_NAME
)
MATCH_CODE_ALL_FLAGS -> Contract.FlagsTable.TABLE_NAME
else -> null
@@ -128,6 +124,7 @@
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
+ if (!::mainDispatcher.isInitialized) return null
if (uriMatcher.match(uri) != MATCH_CODE_ALL_SELECTIONS) {
throw UnsupportedOperationException()
}
@@ -142,6 +139,7 @@
selectionArgs: Array<out String>?,
sortOrder: String?,
): Cursor? {
+ if (!::mainDispatcher.isInitialized) return null
return runBlocking("$TAG#query", mainDispatcher) {
when (uriMatcher.match(uri)) {
MATCH_CODE_ALL_AFFORDANCES -> queryAffordances()
@@ -163,11 +161,8 @@
return 0
}
- override fun delete(
- uri: Uri,
- selection: String?,
- selectionArgs: Array<out String>?,
- ): Int {
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
+ if (!::mainDispatcher.isInitialized) return 0
if (uriMatcher.match(uri) != MATCH_CODE_ALL_SELECTIONS) {
throw UnsupportedOperationException()
}
@@ -232,11 +227,7 @@
throw IllegalArgumentException("Cannot insert selection, affordance ID was empty!")
}
- val success =
- interactor.select(
- slotId = slotId,
- affordanceId = affordanceId,
- )
+ val success = interactor.select(slotId = slotId, affordanceId = affordanceId)
return if (success) {
Log.d(TAG, "Successfully selected $affordanceId for slot $slotId")
@@ -318,22 +309,14 @@
)
.apply {
interactor.getSlotPickerRepresentations().forEach { representation ->
- addRow(
- arrayOf(
- representation.id,
- representation.maxSelectedAffordances,
- )
- )
+ addRow(arrayOf(representation.id, representation.maxSelectedAffordances))
}
}
}
private suspend fun queryFlags(): Cursor {
return MatrixCursor(
- arrayOf(
- Contract.FlagsTable.Columns.NAME,
- Contract.FlagsTable.Columns.VALUE,
- )
+ arrayOf(Contract.FlagsTable.Columns.NAME, Contract.FlagsTable.Columns.VALUE)
)
.apply {
interactor.getPickerFlags().forEach { flag ->
@@ -351,10 +334,7 @@
}
}
- private suspend fun deleteSelection(
- uri: Uri,
- selectionArgs: Array<out String>?,
- ): Int {
+ private suspend fun deleteSelection(uri: Uri, selectionArgs: Array<out String>?): Int {
if (selectionArgs == null) {
throw IllegalArgumentException(
"Cannot delete selection, selection arguments not included!"
@@ -372,11 +352,7 @@
)
}
- val deleted =
- interactor.unselect(
- slotId = slotId,
- affordanceId = affordanceId,
- )
+ val deleted = interactor.unselect(slotId = slotId, affordanceId = affordanceId)
return if (deleted) {
Log.d(TAG, "Successfully unselected $affordanceId for slot $slotId")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index df0f10a..416eaba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -24,12 +24,6 @@
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
-import androidx.constraintlayout.widget.ConstraintSet
-import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
-import androidx.constraintlayout.widget.ConstraintSet.END
-import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
-import androidx.constraintlayout.widget.ConstraintSet.START
-import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
@@ -47,7 +41,6 @@
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
-import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder
@@ -128,7 +121,7 @@
keyguardStatusViewComponentFactory.build(
LayoutInflater.from(context).inflate(R.layout.keyguard_status_view, null)
as KeyguardStatusView,
- context.display
+ context.display,
)
val controller = statusViewComponent.keyguardStatusViewController
controller.init()
@@ -143,29 +136,12 @@
initializeViews()
if (!SceneContainerFlag.isEnabled) {
- if (ComposeLockscreen.isEnabled) {
- val composeView =
- createLockscreen(
- context = context,
- viewModelFactory = lockscreenContentViewModelFactory,
- blueprints = lockscreenSceneBlueprintsLazy.get(),
- )
- composeView.id = View.generateViewId()
- val cs = ConstraintSet()
- cs.clone(keyguardRootView)
- cs.connect(composeView.id, START, PARENT_ID, START)
- cs.connect(composeView.id, END, PARENT_ID, END)
- cs.connect(composeView.id, TOP, PARENT_ID, TOP)
- cs.connect(composeView.id, BOTTOM, PARENT_ID, BOTTOM)
- keyguardRootView.addView(composeView)
- } else {
- KeyguardBlueprintViewBinder.bind(
- keyguardRootView,
- keyguardBlueprintViewModel,
- keyguardClockViewModel,
- smartspaceViewModel,
- )
- }
+ KeyguardBlueprintViewBinder.bind(
+ keyguardRootView,
+ keyguardBlueprintViewModel,
+ keyguardClockViewModel,
+ smartspaceViewModel,
+ )
}
if (deviceEntryUnlockTrackerViewBinder.isPresent) {
deviceEntryUnlockTrackerViewBinder.get().bind(keyguardRootView)
@@ -247,7 +223,7 @@
LockscreenContent(
viewModelFactory = viewModelFactory,
blueprints = sceneBlueprints,
- clockInteractor = clockInteractor
+ clockInteractor = clockInteractor,
)
) {
Content(modifier = Modifier.fillMaxSize())
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3b1569d..1a0525d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -42,6 +42,7 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
import static com.android.systemui.Flags.relockWithPowerButtonImmediately;
+import static com.android.systemui.Flags.simPinBouncerReset;
import static com.android.systemui.Flags.translucentOccludingActivityFix;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
@@ -238,7 +239,6 @@
private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000;
private static final boolean DEBUG = KeyguardConstants.DEBUG;
- private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
private final static String TAG = "KeyguardViewMediator";
@@ -649,11 +649,8 @@
@Override
public void onSimStateChanged(int subId, int slotId, int simState) {
-
- if (DEBUG_SIM_STATES) {
- Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
- + ",state=" + simState + ")");
- }
+ Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
+ + ",state=" + TelephonyManager.simStateToString(simState) + ")");
int size = mKeyguardStateCallbacks.size();
boolean simPinSecure = mUpdateMonitor.isSimPinSecure();
@@ -686,7 +683,7 @@
synchronized (KeyguardViewMediator.this) {
if (shouldWaitForProvisioning()) {
if (!mShowing) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing,"
+ Log.d(TAG, "ICC_ABSENT isn't showing,"
+ " we need to show the keyguard since the "
+ "device isn't provisioned yet.");
doKeyguardLocked(null);
@@ -698,11 +695,21 @@
// MVNO SIMs can become transiently NOT_READY when switching networks,
// so we should only lock when they are ABSENT.
if (lastSimStateWasLocked) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
+ Log.d(TAG, "SIM moved to ABSENT when the "
+ "previous state was locked. Reset the state.");
resetStateLocked();
}
mSimWasLocked.append(slotId, false);
+ } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) {
+ if (simPinBouncerReset()) {
+ // Support eSIM disablement, and do not clear `mSimWasLocked`.
+ // NOT_READY could just be a temporary state
+ if (lastSimStateWasLocked) {
+ Log.d(TAG, "SIM moved to NOT_READY when the "
+ + "previous state was locked. Reset the state.");
+ resetStateLocked();
+ }
+ }
}
}
break;
@@ -712,7 +719,7 @@
mSimWasLocked.append(slotId, true);
mPendingPinLock = true;
if (!mShowing) {
- if (DEBUG_SIM_STATES) Log.d(TAG,
+ Log.d(TAG,
"INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
+ "showing; need to show keyguard so user can enter sim pin");
doKeyguardLocked(null);
@@ -724,11 +731,11 @@
case TelephonyManager.SIM_STATE_PERM_DISABLED:
synchronized (KeyguardViewMediator.this) {
if (!mShowing) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and "
+ Log.d(TAG, "PERM_DISABLED and "
+ "keygaurd isn't showing.");
doKeyguardLocked(null);
} else {
- if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+ Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+ "show permanently disabled message in lockscreen.");
resetStateLocked();
}
@@ -736,9 +743,9 @@
break;
case TelephonyManager.SIM_STATE_READY:
synchronized (KeyguardViewMediator.this) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
+ Log.d(TAG, "READY, reset state? " + mShowing);
if (mShowing && mSimWasLocked.get(slotId, false)) {
- if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to READY when the "
+ Log.d(TAG, "SIM moved to READY when the "
+ "previously was locked. Reset the state.");
mSimWasLocked.append(slotId, false);
resetStateLocked();
@@ -746,7 +753,7 @@
}
break;
default:
- if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
+ Log.v(TAG, "Unspecific state: " + simState);
break;
}
}
@@ -1682,6 +1689,12 @@
});
mJavaAdapter.alwaysCollectFlow(communalViewModel.getTransitionFromOccludedEnded(),
getFinishedCallbackConsumer());
+
+ // System ready can be invoked in the middle of user switching, so check for this state
+ // and issue the call manually as that important event was missed.
+ if (mUserTracker.isUserSwitching()) {
+ mUpdateCallback.onUserSwitching(mUserTracker.getUserId());
+ }
}
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 52323a5..30babe6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
+import android.util.Log
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.Flags.communalSceneKtfRefactor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
@@ -76,7 +77,7 @@
override fun start() {
listenForPrimaryBouncerToGone()
listenForPrimaryBouncerToAsleep()
- listenForPrimaryBouncerToLockscreenHubOrOccluded()
+ listenForPrimaryBouncerNotShowing()
listenForPrimaryBouncerToDreamingLockscreenHosted()
listenForTransitionToCamera(scope, keyguardInteractor)
}
@@ -86,7 +87,7 @@
.transition(
edge = Edge.INVALID,
edgeWithoutSceneContainer =
- Edge.create(from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE)
+ Edge.create(from = KeyguardState.PRIMARY_BOUNCER, to = KeyguardState.GONE),
)
.map<TransitionStep, Boolean?> { it.value > TO_GONE_SURFACE_BEHIND_VISIBLE_THRESHOLD }
.onStart {
@@ -102,7 +103,7 @@
}
}
- private fun listenForPrimaryBouncerToLockscreenHubOrOccluded() {
+ private fun listenForPrimaryBouncerNotShowing() {
if (SceneContainerFlag.isEnabled) return
if (KeyguardWmStateRefactor.isEnabled) {
scope.launch {
@@ -110,7 +111,7 @@
.sample(
powerInteractor.isAwake,
keyguardInteractor.isActiveDreamLockscreenHosted,
- communalSceneInteractor.isIdleOnCommunal
+ communalSceneInteractor.isIdleOnCommunal,
)
.filterRelevantKeyguardStateAnd { (isBouncerShowing, _, _, _) ->
// TODO(b/307976454) - See if we need to listen for SHOW_WHEN_LOCKED
@@ -138,27 +139,34 @@
} else {
scope.launch {
keyguardInteractor.primaryBouncerShowing
+ .filterRelevantKeyguardStateAnd { isBouncerShowing -> !isBouncerShowing }
.sample(
powerInteractor.isAwake,
- keyguardInteractor.isKeyguardOccluded,
keyguardInteractor.isDreaming,
- keyguardInteractor.isActiveDreamLockscreenHosted,
communalSceneInteractor.isIdleOnCommunal,
)
- .filterRelevantKeyguardStateAnd {
- (isBouncerShowing, isAwake, _, _, isActiveDreamLockscreenHosted, _) ->
- !isBouncerShowing && isAwake && !isActiveDreamLockscreenHosted
- }
- .collect { (_, _, occluded, isDreaming, _, isIdleOnCommunal) ->
+ .collect { (_, isAwake, isDreaming, isIdleOnCommunal) ->
+ val isOccluded = keyguardInteractor.isKeyguardOccluded.value
val toState =
- if (occluded && !isDreaming) {
- KeyguardState.OCCLUDED
- } else if (isIdleOnCommunal) {
- KeyguardState.GLANCEABLE_HUB
- } else if (isDreaming) {
- KeyguardState.DREAMING
+ if (isAwake) {
+ if (isOccluded && !isDreaming) {
+ KeyguardState.OCCLUDED
+ } else if (isIdleOnCommunal) {
+ KeyguardState.GLANCEABLE_HUB
+ } else if (isDreaming) {
+ KeyguardState.DREAMING
+ } else {
+ KeyguardState.LOCKSCREEN
+ }
} else {
- KeyguardState.LOCKSCREEN
+ // This shouldn't necessarily happen, but there's a bug in the
+ // bouncer logic which is incorrectly showing/hiding rapidly
+ Log.i(
+ TAG,
+ "Going back to sleeping state to correct an attempt to " +
+ "show bouncer",
+ )
+ keyguardInteractor.asleepKeyguardState.value
}
startTransitionTo(toState)
}
@@ -255,6 +263,7 @@
}
companion object {
+ private const val TAG = "FromPrimaryBouncerTransitionInteractor"
private val DEFAULT_DURATION = 300.milliseconds
val TO_AOD_DURATION = DEFAULT_DURATION
val TO_DOZING_DURATION = DEFAULT_DURATION
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index 7afc759..6932eb5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -25,13 +25,13 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
-import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -64,7 +64,7 @@
/** Current BlueprintId */
val blueprintId =
shadeInteractor.isShadeLayoutWide.map { isShadeLayoutWide ->
- val useSplitShade = isShadeLayoutWide && !ComposeLockscreen.isEnabled
+ val useSplitShade = isShadeLayoutWide && !SceneContainerFlag.isEnabled
when {
useSplitShade -> SplitShadeKeyguardBlueprint.ID
else -> DefaultKeyguardBlueprint.DEFAULT
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
index 8495778..eb9b07a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt
@@ -21,7 +21,7 @@
import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.DismissAction
import com.android.systemui.keyguard.shared.model.KeyguardDone
@@ -29,13 +29,12 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolver
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -61,14 +60,11 @@
transitionInteractor: KeyguardTransitionInteractor,
val dismissInteractor: KeyguardDismissInteractor,
@Application private val applicationScope: CoroutineScope,
- sceneInteractor: dagger.Lazy<SceneInteractor>,
- deviceEntryInteractor: dagger.Lazy<DeviceEntryInteractor>,
- quickSettingsSceneFamilyResolver: dagger.Lazy<QuickSettingsSceneFamilyResolver>,
- notifShadeSceneFamilyResolver: dagger.Lazy<NotifShadeSceneFamilyResolver>,
+ sceneInteractor: Lazy<SceneInteractor>,
+ deviceUnlockedInteractor: Lazy<DeviceUnlockedInteractor>,
powerInteractor: PowerInteractor,
alternateBouncerInteractor: AlternateBouncerInteractor,
- keyguardInteractor: dagger.Lazy<KeyguardInteractor>,
- shadeInteractor: dagger.Lazy<ShadeInteractor>,
+ shadeInteractor: Lazy<ShadeInteractor>,
) {
val dismissAction: Flow<DismissAction> = repository.dismissAction
@@ -106,18 +102,18 @@
if (SceneContainerFlag.isEnabled) {
combine(
sceneInteractor.get().currentScene,
- deviceEntryInteractor.get().isUnlocked,
- ) { scene, isUnlocked ->
- isUnlocked &&
- (quickSettingsSceneFamilyResolver.get().includesScene(scene) ||
- notifShadeSceneFamilyResolver.get().includesScene(scene))
+ deviceUnlockedInteractor.get().deviceUnlockStatus,
+ ) { scene, unlockStatus ->
+ unlockStatus.isUnlocked &&
+ (scene == Scenes.QuickSettings || scene == Scenes.Shade)
}
.distinctUntilChanged()
} else if (ComposeBouncerFlags.isOnlyComposeBouncerEnabled()) {
- shadeInteractor.get().isAnyExpanded.sample(
- keyguardInteractor.get().isKeyguardDismissible
- ) { isAnyExpanded, isKeyguardDismissible ->
- isAnyExpanded && isKeyguardDismissible
+ combine(
+ shadeInteractor.get().isAnyExpanded,
+ deviceUnlockedInteractor.get().deviceUnlockStatus,
+ ) { isAnyExpanded, deviceUnlockStatus ->
+ isAnyExpanded && deviceUnlockStatus.isUnlocked
}
} else {
flow {
@@ -132,7 +128,7 @@
merge(
finishedTransitionToGone,
isOnShadeWhileUnlocked.filter { it }.map {},
- dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction
+ dismissInteractor.dismissKeyguardRequestWithImmediateDismissAction,
)
.sample(dismissAction)
.filterNot { it is DismissAction.None }
@@ -142,11 +138,11 @@
combine(
transitionInteractor.isFinishedIn(
scene = Scenes.Gone,
- stateWithoutSceneContainer = GONE
+ stateWithoutSceneContainer = GONE,
),
transitionInteractor.isFinishedIn(
scene = Scenes.Bouncer,
- stateWithoutSceneContainer = PRIMARY_BOUNCER
+ stateWithoutSceneContainer = PRIMARY_BOUNCER,
),
alternateBouncerInteractor.isVisible,
isOnShadeWhileUnlocked,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt
index d7e6bdb..4457f1d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt
@@ -23,10 +23,12 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.shared.model.DismissAction
import com.android.systemui.keyguard.shared.model.KeyguardDone
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.Utils.Companion.toQuad
@@ -35,6 +37,7 @@
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
@@ -56,6 +59,7 @@
trustRepository: TrustRepository,
alternateBouncerInteractor: AlternateBouncerInteractor,
powerInteractor: PowerInteractor,
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
) {
/*
* Updates when a biometric has authenticated the device and is requesting to dismiss
@@ -76,9 +80,9 @@
primaryBouncerInteractor.isShowing,
alternateBouncerInteractor.isVisible,
powerInteractor.isInteractive,
- ::Triple
+ ::Triple,
),
- ::toQuad
+ ::toQuad,
)
.filter { (trustModel, primaryBouncerShowing, altBouncerShowing, interactive) ->
val bouncerShowing = primaryBouncerShowing || altBouncerShowing
@@ -144,9 +148,7 @@
*
* TODO(b/358412565): Support dismiss messages.
*/
- fun dismissKeyguardWithCallback(
- callback: IKeyguardDismissCallback?,
- ) {
+ fun dismissKeyguardWithCallback(callback: IKeyguardDismissCallback?) {
scope.launch {
withContext(mainDispatcher) {
if (callback != null) {
@@ -163,4 +165,14 @@
}
}
}
+
+ init {
+ if (KeyguardWmStateRefactor.isEnabled) {
+ scope.launch {
+ keyguardTransitionInteractor.currentKeyguardState
+ .filter { it == KeyguardState.GONE }
+ .collect { dismissCallbackRegistry.notifyDismissSucceeded() }
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
index 44aafab..ad1a32e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt
@@ -76,7 +76,7 @@
.filter { enabled -> !enabled }
.sampleCombine(
internalTransitionInteractor.currentTransitionInfoInternal,
- biometricSettingsRepository.isCurrentUserInLockdown
+ biometricSettingsRepository.isCurrentUserInLockdown,
)
.map { (_, transitionInfo, inLockdown) ->
// ...we hide the keyguard, if it's showing and we're not in lockdown. In that case,
@@ -91,12 +91,18 @@
*/
scope.launch {
if (!SceneContainerFlag.isEnabled) {
- showKeyguardWhenReenabled
- .filter { shouldDismiss -> shouldDismiss }
- .collect {
- keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
- "keyguard disabled"
- )
+ repository.isKeyguardEnabled
+ .filter { enabled -> !enabled }
+ .sampleCombine(
+ biometricSettingsRepository.isCurrentUserInLockdown,
+ internalTransitionInteractor.currentTransitionInfoInternal,
+ )
+ .collect { (_, inLockdown, currentTransitionInfo) ->
+ if (currentTransitionInfo.to != KeyguardState.GONE && !inLockdown) {
+ keyguardDismissTransitionInteractor.startDismissKeyguardTransition(
+ "keyguard disabled"
+ )
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt
index 420fbd4..7fd348b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt
@@ -20,6 +20,7 @@
import android.os.RemoteException
import com.android.internal.policy.IKeyguardStateCallback
import com.android.systemui.CoreStartable
+import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -27,13 +28,13 @@
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import javax.inject.Inject
/**
* Updates KeyguardStateCallbacks provided to KeyguardService with KeyguardTransitionInteractor
@@ -50,6 +51,8 @@
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val selectedUserInteractor: SelectedUserInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val trustInteractor: TrustInteractor,
+ private val simBouncerInteractor: SimBouncerInteractor,
) : CoreStartable {
private val callbacks = mutableListOf<IKeyguardStateCallback>()
@@ -60,21 +63,19 @@
applicationScope.launch {
combine(
- selectedUserInteractor.selectedUser,
- keyguardTransitionInteractor.currentKeyguardState,
- ::Pair
- ).collectLatest { (selectedUser, currentState) ->
- val iterator = callbacks.iterator()
+ selectedUserInteractor.selectedUser,
+ keyguardTransitionInteractor.currentKeyguardState,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep,
+ ::Triple,
+ )
+ .collectLatest { (selectedUser, _, _) ->
+ val iterator = callbacks.iterator()
withContext(backgroundDispatcher) {
while (iterator.hasNext()) {
val callback = iterator.next()
try {
- callback.onShowingStateChanged(
- currentState != KeyguardState.GONE,
- selectedUser
- )
- callback.onInputRestrictedStateChanged(
- currentState != KeyguardState.GONE)
+ callback.onShowingStateChanged(!isIdleInGone(), selectedUser)
+ callback.onInputRestrictedStateChanged(!isIdleInGone())
} catch (e: RemoteException) {
if (e is DeadObjectException) {
iterator.remove()
@@ -84,10 +85,58 @@
}
}
}
+
+ applicationScope.launch {
+ trustInteractor.isTrusted.collectLatest { isTrusted ->
+ val iterator = callbacks.iterator()
+ withContext(backgroundDispatcher) {
+ while (iterator.hasNext()) {
+ val callback = iterator.next()
+ try {
+ callback.onTrustedChanged(isTrusted)
+ } catch (e: RemoteException) {
+ if (e is DeadObjectException) {
+ iterator.remove()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ applicationScope.launch {
+ simBouncerInteractor.isAnySimSecure.collectLatest { isSimSecured ->
+ val iterator = callbacks.iterator()
+ withContext(backgroundDispatcher) {
+ while (iterator.hasNext()) {
+ val callback = iterator.next()
+ try {
+ callback.onSimSecureStateChanged(isSimSecured)
+ } catch (e: RemoteException) {
+ if (e is DeadObjectException) {
+ iterator.remove()
+ }
+ }
+ }
+ }
+ }
+ }
}
fun addCallback(callback: IKeyguardStateCallback) {
KeyguardWmStateRefactor.isUnexpectedlyInLegacyMode()
callbacks.add(callback)
+
+ // Send initial values to new callbacks.
+ callback.onShowingStateChanged(!isIdleInGone(), selectedUserInteractor.getSelectedUserId())
+ callback.onInputRestrictedStateChanged(!isIdleInGone())
+ callback.onTrustedChanged(trustInteractor.isTrusted.value)
+ callback.onSimSecureStateChanged(simBouncerInteractor.isAnySimSecure.value)
}
-}
\ No newline at end of file
+
+ /** Whether we're in KeyguardState.GONE and haven't started a transition to another state. */
+ private fun isIdleInGone(): Boolean {
+ return keyguardTransitionInteractor.getCurrentState() == KeyguardState.GONE &&
+ keyguardTransitionInteractor.getStartedState() == KeyguardState.GONE
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index e19b72e..c4f231d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -77,7 +77,7 @@
MutableSharedFlow<Float>(
replay = 1,
extraBufferCapacity = 2,
- onBufferOverflow = BufferOverflow.DROP_OLDEST
+ onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
.also { it.tryEmit(0f) }
}
@@ -97,8 +97,8 @@
SharingStarted.Eagerly,
WithPrev(
sceneInteractor.transitionState.value,
- sceneInteractor.transitionState.value
- )
+ sceneInteractor.transitionState.value,
+ ),
)
/**
@@ -156,7 +156,7 @@
Log.e(
TAG,
"STARTED step ($startedStep) was preceded by a RUNNING step " +
- "($prevStep), which should never happen. Things could go badly here."
+ "($prevStep), which should never happen. Things could go badly here.",
)
}
}
@@ -202,7 +202,7 @@
transitionMap.getOrPut(mappedEdge) {
MutableSharedFlow(
extraBufferCapacity = 10,
- onBufferOverflow = BufferOverflow.DROP_OLDEST
+ onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
}
@@ -262,7 +262,7 @@
is Edge.StateToState ->
Edge.create(
from = edge.from?.mapToSceneContainerState(),
- to = edge.to?.mapToSceneContainerState()
+ to = edge.to?.mapToSceneContainerState(),
)
is Edge.SceneToState -> Edge.create(UNDEFINED, edge.to)
is Edge.StateToScene -> Edge.create(edge.from, UNDEFINED)
@@ -286,9 +286,7 @@
* The value will be `0` (or close to `0`, due to float point arithmetic) if not in this step or
* `1` when fully in the given state.
*/
- fun transitionValue(
- state: KeyguardState,
- ): Flow<Float> {
+ fun transitionValue(state: KeyguardState): Flow<Float> {
if (SceneContainerFlag.isEnabled && state != state.mapToSceneContainerState()) {
Log.e(TAG, "SceneContainer is enabled but a deprecated state $state is used.")
return transitionValue(state.mapToSceneContainerScene()!!, state)
@@ -369,10 +367,9 @@
.stateIn(scope, SharingStarted.Eagerly, OFF)
val isInTransition =
- combine(
- isInTransitionWhere({ true }, { true }),
- sceneInteractor.transitionState,
- ) { isKeyguardTransitioning, sceneTransitionState ->
+ combine(isInTransitionWhere({ true }, { true }), sceneInteractor.transitionState) {
+ isKeyguardTransitioning,
+ sceneTransitionState ->
isKeyguardTransitioning ||
(SceneContainerFlag.isEnabled && sceneTransitionState.isTransitioning())
}
@@ -465,6 +462,10 @@
return currentKeyguardState.replayCache.last()
}
+ fun getStartedState(): KeyguardState {
+ return startedKeyguardTransitionStep.value.to
+ }
+
private val finishedKeyguardState: StateFlow<KeyguardState> =
repository.transitions
.filter { it.transitionState == TransitionState.FINISHED }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index ed82159..deb0b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -59,7 +59,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
-import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
@@ -72,6 +71,7 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.CrossFadeHelper
import com.android.systemui.statusbar.VibratorHelper
@@ -241,7 +241,7 @@
disposables +=
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
- if (ComposeLockscreen.isEnabled) {
+ if (SceneContainerFlag.isEnabled) {
view.setViewTreeOnBackPressedDispatcherOwner(
object : OnBackPressedDispatcherOwner {
override val onBackPressedDispatcher =
@@ -261,10 +261,7 @@
->
if (biometricMessage?.message != null) {
chipbarCoordinator!!.displayView(
- createChipbarInfo(
- biometricMessage.message,
- R.drawable.ic_lock,
- )
+ createChipbarInfo(biometricMessage.message, R.drawable.ic_lock)
)
} else {
chipbarCoordinator!!.removeView(ID, "occludingAppMsgNull")
@@ -327,12 +324,16 @@
.getDimensionPixelSize(R.dimen.shelf_appear_translation)
.stateIn(this)
viewModel.isNotifIconContainerVisible.collect { isVisible ->
- childViews[aodNotificationIconContainerId]
- ?.setAodNotifIconContainerIsVisible(
- isVisible,
- iconsAppearTranslationPx.value,
- screenOffAnimationController,
- )
+ if (isVisible.value) {
+ blueprintViewModel.refreshBlueprint()
+ } else {
+ childViews[aodNotificationIconContainerId]
+ ?.setAodNotifIconContainerIsVisible(
+ isVisible,
+ iconsAppearTranslationPx.value,
+ screenOffAnimationController,
+ )
+ }
}
}
@@ -382,7 +383,7 @@
if (msdlFeedback()) {
msdlPlayer?.playToken(
MSDLToken.UNLOCK,
- authInteractionProperties
+ authInteractionProperties,
)
} else {
vibratorHelper.performHapticFeedback(
@@ -398,7 +399,7 @@
if (msdlFeedback()) {
msdlPlayer?.playToken(
MSDLToken.FAILURE,
- authInteractionProperties
+ authInteractionProperties,
)
} else {
vibratorHelper.performHapticFeedback(
@@ -425,7 +426,7 @@
blueprintViewModel,
clockViewModel,
childViews,
- burnInParams
+ burnInParams,
)
)
@@ -464,11 +465,7 @@
*/
private fun createChipbarInfo(message: String, @DrawableRes icon: Int): ChipbarInfo {
return ChipbarInfo(
- startIcon =
- TintedIcon(
- Icon.Resource(icon, null),
- ChipbarInfo.DEFAULT_ICON_TINT,
- ),
+ startIcon = TintedIcon(Icon.Resource(icon, null), ChipbarInfo.DEFAULT_ICON_TINT),
text = Text.Loaded(message),
endItem = null,
vibrationEffect = null,
@@ -499,7 +496,7 @@
oldLeft: Int,
oldTop: Int,
oldRight: Int,
- oldBottom: Int
+ oldBottom: Int,
) {
// After layout, ensure the notifications are positioned correctly
childViews[nsslPlaceholderId]?.let { notificationListPlaceholder ->
@@ -515,7 +512,7 @@
viewModel.onNotificationContainerBoundsChanged(
notificationListPlaceholder.top.toFloat(),
notificationListPlaceholder.bottom.toFloat(),
- animate = shouldAnimate
+ animate = shouldAnimate,
)
}
@@ -531,7 +528,7 @@
Int.MAX_VALUE
} else {
view.getTop()
- }
+ },
)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
index c6efcfa..4cf3c4e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
@@ -25,20 +25,18 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
+import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-data class TransitionData(
- val config: Config,
- val start: Long = System.currentTimeMillis(),
-)
+data class TransitionData(val config: Config, val start: Long = System.currentTimeMillis())
class KeyguardBlueprintViewModel
@Inject
constructor(
@Main private val handler: Handler,
- keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
+ private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
) {
val blueprint = keyguardBlueprintInteractor.blueprint
val blueprintId = keyguardBlueprintInteractor.blueprintId
@@ -76,6 +74,9 @@
}
}
+ fun refreshBlueprint(type: Type = Type.NoTransition) =
+ keyguardBlueprintInteractor.refreshBlueprint(type)
+
fun updateTransitions(data: TransitionData?, mutate: MutableSet<Transition>.() -> Unit) {
runningTransitions.mutate()
@@ -95,7 +96,7 @@
Log.w(
TAG,
"runTransition: skipping ${transition::class.simpleName}: " +
- "currentPriority=$currentPriority; config=$config"
+ "currentPriority=$currentPriority; config=$config",
)
}
apply()
@@ -106,7 +107,7 @@
Log.i(
TAG,
"runTransition: running ${transition::class.simpleName}: " +
- "currentPriority=$currentPriority; config=$config"
+ "currentPriority=$currentPriority; config=$config",
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 73028c5..36f684e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -25,10 +25,10 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
-import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.ClockSizeSetting
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
@@ -56,10 +56,9 @@
var burnInLayer: Layer? = null
val clockSize: StateFlow<ClockSize> =
- combine(
- keyguardClockInteractor.selectedClockSize,
- keyguardClockInteractor.clockSize,
- ) { selectedSize, clockSize ->
+ combine(keyguardClockInteractor.selectedClockSize, keyguardClockInteractor.clockSize) {
+ selectedSize,
+ clockSize ->
if (selectedSize == ClockSizeSetting.SMALL) ClockSize.SMALL else clockSize
}
.stateIn(
@@ -80,10 +79,7 @@
val currentClock = keyguardClockInteractor.currentClock
val hasCustomWeatherDataDisplay =
- combine(
- isLargeClockVisible,
- currentClock,
- ) { isLargeClock, currentClock ->
+ combine(isLargeClockVisible, currentClock) { isLargeClock, currentClock ->
currentClock?.let { clock ->
val face = if (isLargeClock) clock.largeClock else clock.smallClock
face.config.hasCustomWeatherDataDisplay
@@ -93,14 +89,14 @@
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue =
- currentClock.value?.largeClock?.config?.hasCustomWeatherDataDisplay ?: false
+ currentClock.value?.largeClock?.config?.hasCustomWeatherDataDisplay ?: false,
)
val clockShouldBeCentered: StateFlow<Boolean> =
keyguardClockInteractor.clockShouldBeCentered.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false
+ initialValue = false,
)
// To translate elements below smartspace in weather clock to avoid overlapping between date
@@ -111,7 +107,7 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false
+ initialValue = false,
)
val currentClockLayout: StateFlow<ClockLayout> =
@@ -145,7 +141,7 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = ClockLayout.SMALL_CLOCK
+ initialValue = ClockLayout.SMALL_CLOCK,
)
val hasCustomPositionUpdatedAnimation: StateFlow<Boolean> =
@@ -156,7 +152,7 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false
+ initialValue = false,
)
/** Calculates the top margin for the small clock. */
@@ -164,10 +160,10 @@
val statusBarHeight = systemBarUtils.getStatusBarHeaderHeightKeyguard()
return if (shadeInteractor.isShadeLayoutWide.value) {
resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) -
- if (ComposeLockscreen.isEnabled) statusBarHeight else 0
+ if (SceneContainerFlag.isEnabled) statusBarHeight else 0
} else {
resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
- if (!ComposeLockscreen.isEnabled) statusBarHeight else 0
+ if (!SceneContainerFlag.isEnabled) statusBarHeight else 0
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
index ecae079..3b266f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModel.kt
@@ -21,13 +21,11 @@
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
-import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.scene.shared.model.Overlays
-import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
@@ -71,9 +69,8 @@
addAll(
when (shadeMode) {
- ShadeMode.Single -> fullscreenShadeActions()
- ShadeMode.Split ->
- fullscreenShadeActions(transitionKey = ToSplitShade)
+ ShadeMode.Single -> singleShadeActions()
+ ShadeMode.Split -> splitShadeActions()
ShadeMode.Dual -> dualShadeActions()
}
)
@@ -84,18 +81,26 @@
.collect { setActions(it) }
}
- private fun fullscreenShadeActions(
- transitionKey: TransitionKey? = null
- ): Array<Pair<UserAction, UserActionResult>> {
- val notifShadeSceneKey = UserActionResult(SceneFamilies.NotifShade, transitionKey)
- val qsShadeSceneKey = UserActionResult(SceneFamilies.QuickSettings, transitionKey)
+ private fun singleShadeActions(): Array<Pair<UserAction, UserActionResult>> {
return arrayOf(
// Swiping down, not from the edge, always goes to shade.
- Swipe.Down to notifShadeSceneKey,
- swipeDown(pointerCount = 2) to notifShadeSceneKey,
+ Swipe.Down to Scenes.Shade,
+ swipeDown(pointerCount = 2) to Scenes.Shade,
// Swiping down from the top edge goes to QS.
- swipeDownFromTop(pointerCount = 1) to qsShadeSceneKey,
- swipeDownFromTop(pointerCount = 2) to qsShadeSceneKey,
+ swipeDownFromTop(pointerCount = 1) to Scenes.QuickSettings,
+ swipeDownFromTop(pointerCount = 2) to Scenes.QuickSettings,
+ )
+ }
+
+ private fun splitShadeActions(): Array<Pair<UserAction, UserActionResult>> {
+ val splitShadeSceneKey = UserActionResult(Scenes.Shade, ToSplitShade)
+ return arrayOf(
+ // Swiping down, not from the edge, always goes to shade.
+ Swipe.Down to splitShadeSceneKey,
+ swipeDown(pointerCount = 2) to splitShadeSceneKey,
+ // Swiping down from the top edge goes to QS.
+ swipeDownFromTop(pointerCount = 1) to splitShadeSceneKey,
+ swipeDownFromTop(pointerCount = 2) to splitShadeSceneKey,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoader.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoader.kt
index 53cc15b..7b55dac8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoader.kt
@@ -42,7 +42,6 @@
import android.support.v4.media.MediaMetadataCompat
import android.text.TextUtils
import android.util.Log
-import android.util.Pair
import androidx.media.utils.MediaConstants
import com.android.app.tracing.coroutines.traceCoroutine
import com.android.systemui.dagger.SysUISingleton
@@ -70,6 +69,7 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.delay
import kotlinx.coroutines.ensureActive
/** Loads media information from media style [StatusBarNotification] classes. */
@@ -85,7 +85,7 @@
private val imageLoader: ImageLoader,
private val statusBarManager: StatusBarManager,
) {
- private val mediaProcessingJobs = ConcurrentHashMap<JobKey, Job>()
+ private val mediaProcessingJobs = ConcurrentHashMap<String, Job>()
private val artworkWidth: Int =
context.resources.getDimensionPixelSize(
@@ -97,7 +97,7 @@
private val themeText =
com.android.settingslib.Utils.getColorAttr(
context,
- com.android.internal.R.attr.textColorPrimary
+ com.android.internal.R.attr.textColorPrimary,
)
.defaultColor
@@ -112,11 +112,14 @@
* load will be cancelled.
*/
suspend fun loadMediaData(key: String, sbn: StatusBarNotification): MediaDataLoaderResult? {
- logD(TAG) { "Loading media data for $key..." }
- val jobKey = JobKey(key, sbn)
val loadMediaJob = backgroundScope.async { loadMediaDataInBackground(key, sbn) }
- loadMediaJob.invokeOnCompletion { mediaProcessingJobs.remove(jobKey) }
- val existingJob = mediaProcessingJobs.put(jobKey, loadMediaJob)
+ loadMediaJob.invokeOnCompletion {
+ // We need to make sure we're removing THIS job after cancellation, not
+ // a job that we created later.
+ mediaProcessingJobs.remove(key, loadMediaJob)
+ }
+ val existingJob = mediaProcessingJobs.put(key, loadMediaJob)
+ logD(TAG) { "Loading media data for $key... / existing job: $existingJob" }
existingJob?.cancel("New processing job incoming.")
return loadMediaJob.await()
}
@@ -128,10 +131,15 @@
sbn: StatusBarNotification,
): MediaDataLoaderResult? =
traceCoroutine("MediaDataLoader#loadMediaData") {
+ // We have apps spamming us with quick notification updates which can cause
+ // us to spend significant CPU time loading duplicate data. This debounces
+ // those requests at the cost of a bit of latency.
+ delay(DEBOUNCE_DELAY_MS)
+
val token =
sbn.notification.extras.getParcelable(
Notification.EXTRA_MEDIA_SESSION,
- MediaSession.Token::class.java
+ MediaSession.Token::class.java,
)
if (token == null) {
Log.i(TAG, "Token was null, not loading media info")
@@ -144,7 +152,7 @@
val appInfo =
notification.extras.getParcelable(
Notification.EXTRA_BUILDER_APPLICATION_INFO,
- ApplicationInfo::class.java
+ ApplicationInfo::class.java,
) ?: getAppInfoFromPackage(sbn.packageName)
// App name
@@ -240,7 +248,7 @@
playbackLocation = playbackLocation,
isPlaying = isPlaying,
appUid = appUid,
- isExplicit = isExplicit
+ isExplicit = isExplicit,
)
}
@@ -258,7 +266,7 @@
token: MediaSession.Token,
appName: String,
appIntent: PendingIntent,
- packageName: String
+ packageName: String,
): MediaDataLoaderResult? {
val mediaData =
backgroundScope.async {
@@ -270,7 +278,7 @@
token,
appName,
appIntent,
- packageName
+ packageName,
)
}
return mediaData.await()
@@ -286,7 +294,7 @@
token: MediaSession.Token,
appName: String,
appIntent: PendingIntent,
- packageName: String
+ packageName: String,
): MediaDataLoaderResult? =
traceCoroutine("MediaDataLoader#loadMediaDataForResumption") {
if (desc.title.isNullOrBlank()) {
@@ -338,14 +346,14 @@
appUid = appUid,
isExplicit = isExplicit,
resumeAction = resumeAction,
- resumeProgress = progress
+ resumeProgress = progress,
)
}
private fun createActionsFromState(
packageName: String,
controller: MediaController,
- user: UserHandle
+ user: UserHandle,
): MediaButton? {
if (!mediaFlags.areMediaSessionActionsEnabled(packageName, user)) {
return null
@@ -368,7 +376,7 @@
*/
private fun getDeviceInfoForRemoteCast(
key: String,
- sbn: StatusBarNotification
+ sbn: StatusBarNotification,
): MediaDeviceData? {
val extras = sbn.notification.extras
val deviceName = extras.getCharSequence(Notification.EXTRA_MEDIA_REMOTE_DEVICE, null)
@@ -388,7 +396,7 @@
deviceDrawable,
deviceName,
deviceIntent,
- showBroadcastButton = false
+ showBroadcastButton = false,
)
}
return null
@@ -439,7 +447,7 @@
listOf(
ContentResolver.SCHEME_CONTENT,
ContentResolver.SCHEME_ANDROID_RESOURCE,
- ContentResolver.SCHEME_FILE
+ ContentResolver.SCHEME_FILE,
)
) {
Log.w(TAG, "Invalid album art uri $uri")
@@ -451,7 +459,7 @@
source,
artworkWidth,
artworkHeight,
- allocator = ImageDecoder.ALLOCATOR_SOFTWARE
+ allocator = ImageDecoder.ALLOCATOR_SOFTWARE,
)
}
@@ -459,7 +467,7 @@
uri: Uri,
userId: Int,
appUid: Int,
- packageName: String
+ packageName: String,
): Bitmap? {
try {
val ugm = UriGrantsManager.getService()
@@ -468,7 +476,7 @@
packageName,
ContentProvider.getUriWithoutUserId(uri),
Intent.FLAG_GRANT_READ_URI_PERMISSION,
- ContentProvider.getUserIdFromUri(uri, userId)
+ ContentProvider.getUserIdFromUri(uri, userId),
)
return loadBitmapFromUri(uri)
} catch (e: SecurityException) {
@@ -488,21 +496,20 @@
.loadDrawable(context),
action,
context.getString(R.string.controls_media_resume),
- context.getDrawable(R.drawable.ic_media_play_container)
+ context.getDrawable(R.drawable.ic_media_play_container),
)
}
- private data class JobKey(val key: String, val sbn: StatusBarNotification) :
- Pair<String, StatusBarNotification>(key, sbn)
-
companion object {
private const val TAG = "MediaDataLoader"
private val ART_URIS =
arrayOf(
MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
MediaMetadata.METADATA_KEY_ART_URI,
- MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
+ MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI,
)
+
+ private const val DEBOUNCE_DELAY_MS = 200L
}
/** Returned data from loader. */
@@ -523,6 +530,6 @@
val appUid: Int,
val isExplicit: Boolean,
val resumeAction: Runnable? = null,
- val resumeProgress: Double? = null
+ val resumeProgress: Double? = null,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/resume/MediaResumeListener.kt
index 9ee59d1..ad84a5e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/resume/MediaResumeListener.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media.controls.domain.resume
+import android.annotation.WorkerThread
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
@@ -41,6 +42,7 @@
import com.android.systemui.settings.UserTracker
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Utils
+import com.android.systemui.util.kotlin.logD
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import java.util.concurrent.ConcurrentLinkedQueue
@@ -86,11 +88,12 @@
@VisibleForTesting
val userUnlockReceiver =
object : BroadcastReceiver() {
+ @WorkerThread
override fun onReceive(context: Context, intent: Intent) {
if (Intent.ACTION_USER_UNLOCKED == intent.action) {
val userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
if (userId == currentUserId) {
- backgroundExecutor.execute { loadMediaResumptionControls() }
+ loadMediaResumptionControls()
}
}
}
@@ -109,7 +112,7 @@
override fun addTrack(
desc: MediaDescription,
component: ComponentName,
- browser: ResumeMediaBrowser
+ browser: ResumeMediaBrowser,
) {
val token = browser.token
val appIntent = browser.appIntent
@@ -123,7 +126,7 @@
Log.e(TAG, "Error getting package information", e)
}
- Log.d(TAG, "Adding resume controls for ${browser.userId}: $desc")
+ logD(TAG) { "Adding resume controls for ${browser.userId}: $desc" }
mediaDataManager.addResumptionControls(
browser.userId,
desc,
@@ -131,7 +134,7 @@
token,
appName.toString(),
appIntent,
- component.packageName
+ component.packageName,
)
}
}
@@ -144,8 +147,8 @@
broadcastDispatcher.registerReceiver(
userUnlockReceiver,
unlockFilter,
- null,
- UserHandle.ALL
+ backgroundExecutor,
+ UserHandle.ALL,
)
userTracker.addCallback(userTrackerCallback, mainExecutor)
loadSavedComponents()
@@ -163,7 +166,7 @@
mediaDataManager.setMediaResumptionEnabled(useMediaResumption)
}
},
- Settings.Secure.MEDIA_CONTROLS_RESUME
+ Settings.Secure.MEDIA_CONTROLS_RESUME,
)
}
@@ -197,11 +200,11 @@
}
resumeComponents.add(component to lastPlayed)
}
- Log.d(
- TAG,
+
+ logD(TAG) {
"loaded resume components for $currentUserId: " +
- "${resumeComponents.toArray().contentToString()}"
- )
+ resumeComponents.toArray().contentToString()
+ }
if (needsUpdate) {
// Save any missing times that we had to fill in
@@ -228,7 +231,7 @@
mediaBrowserFactory.create(mediaBrowserCallback, it.first, currentUserId)
browser.findRecentMedia()
} else {
- Log.d(TAG, "User $currentUserId does not have component ${it.first}")
+ logD(TAG) { "User $currentUserId does not have component ${it.first}" }
}
}
}
@@ -240,7 +243,7 @@
data: MediaData,
immediately: Boolean,
receivedSmartspaceCardLatency: Int,
- isSsReactivated: Boolean
+ isSsReactivated: Boolean,
) {
if (useMediaResumption) {
// If this had been started from a resume state, disconnect now that it's live
@@ -281,7 +284,7 @@
mediaBrowserFactory.create(
object : ResumeMediaBrowser.Callback() {
override fun onConnected() {
- Log.d(TAG, "Connected to $componentName")
+ logD(TAG) { "Connected to $componentName" }
}
override fun onError() {
@@ -292,20 +295,20 @@
override fun addTrack(
desc: MediaDescription,
component: ComponentName,
- browser: ResumeMediaBrowser
+ browser: ResumeMediaBrowser,
) {
// Since this is a test, just save the component for later
- Log.d(
- TAG,
+ logD(TAG) {
"Can get resumable media for ${browser.userId} from $componentName"
- )
+ }
+
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
updateResumptionList(componentName)
mediaBrowser = null
}
},
componentName,
- currentUserId
+ currentUserId,
)
mediaBrowser?.testConnection()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
index a9d2a54..38cea5b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
@@ -64,6 +64,7 @@
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -431,6 +432,12 @@
/** Is the communal UI showing */
private var isCommunalShowing: Boolean = false
+ /** Is the primary bouncer showing */
+ private var isPrimaryBouncerShowing: Boolean = false
+
+ /** Is either shade or QS fully expanded */
+ private var isAnyShadeFullyExpanded: Boolean = false
+
/** Is the communal UI showing and not dreaming */
private var onCommunalNotDreaming: Boolean = false
@@ -587,6 +594,20 @@
}
}
+ coroutineScope.launch {
+ shadeInteractor.isAnyFullyExpanded.collect {
+ isAnyShadeFullyExpanded = it
+ updateUserVisibility()
+ }
+ }
+
+ coroutineScope.launch {
+ keyguardInteractor.primaryBouncerShowing.collect {
+ isPrimaryBouncerShowing = it
+ updateUserVisibility()
+ }
+ }
+
if (mediaControlsLockscreenShadeBugFix()) {
coroutineScope.launch {
shadeInteractor.shadeExpansion.collect { expansion ->
@@ -638,6 +659,7 @@
communalShowing && isDreaming && isShadeExpanding
onCommunalNotDreaming = communalShowing && !isDreaming
updateDesiredLocation(forceNoAnimation = true)
+ updateUserVisibility()
}
}
}
@@ -1290,7 +1312,8 @@
val shadeVisible =
isLockScreenVisibleToUser() ||
isLockScreenShadeVisibleToUser() ||
- isHomeScreenShadeVisibleToUser()
+ isHomeScreenShadeVisibleToUser() ||
+ isGlanceableHubVisibleToUser()
val mediaVisible = qsExpanded || hasActiveMediaOrRecommendation
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
shadeVisible && mediaVisible
@@ -1318,6 +1341,10 @@
statusBarStateController.isExpanded
}
+ private fun isGlanceableHubVisibleToUser(): Boolean {
+ return isCommunalShowing && !isPrimaryBouncerShowing && !isAnyShadeFullyExpanded
+ }
+
companion object {
/** Attached in expanded quick settings */
const val LOCATION_QS = 0
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index ff9495d..2961d05 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -57,7 +57,7 @@
private static final float DEVICE_CONNECTED_ALPHA = 1f;
protected List<MediaItem> mMediaItemList = new CopyOnWriteArrayList<>();
- public MediaOutputAdapter(MediaOutputController controller) {
+ public MediaOutputAdapter(MediaSwitchingController controller) {
super(controller);
setHasStableIds(true);
}
@@ -531,8 +531,10 @@
@RequiresApi(34)
private static class Api34Impl {
@DoNotInline
- static View.OnClickListener getClickListenerBasedOnSelectionBehavior(MediaDevice device,
- MediaOutputController controller, View.OnClickListener defaultTransferListener) {
+ static View.OnClickListener getClickListenerBasedOnSelectionBehavior(
+ MediaDevice device,
+ MediaSwitchingController controller,
+ View.OnClickListener defaultTransferListener) {
switch (device.getSelectionBehavior()) {
case SELECTION_BEHAVIOR_NONE:
return null;
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 5958b0a..63a7e01 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -63,7 +63,7 @@
static final int CUSTOMIZED_ITEM_GROUP = 2;
static final int CUSTOMIZED_ITEM_DYNAMIC_GROUP = 3;
- protected final MediaOutputController mController;
+ protected final MediaSwitchingController mController;
private static final int UNMUTE_DEFAULT_VOLUME = 2;
@@ -73,7 +73,7 @@
int mCurrentActivePosition;
private boolean mIsInitVolumeFirstTime;
- public MediaOutputBaseAdapter(MediaOutputController controller) {
+ public MediaOutputBaseAdapter(MediaSwitchingController controller) {
mController = controller;
mIsDragging = false;
mCurrentActivePosition = -1;
@@ -127,7 +127,7 @@
return mCurrentActivePosition;
}
- public MediaOutputController getController() {
+ public MediaSwitchingController getController() {
return mController;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 6cc4dcb..6bc995f3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -65,11 +65,9 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
-/**
- * Base dialog for media output UI
- */
-public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
- MediaOutputController.Callback, Window.Callback {
+/** Base dialog for media output UI */
+public abstract class MediaOutputBaseDialog extends SystemUIDialog
+ implements MediaSwitchingController.Callback, Window.Callback {
private static final String TAG = "MediaOutputDialog";
private static final String EMPTY_TITLE = " ";
@@ -82,7 +80,7 @@
private final RecyclerView.LayoutManager mLayoutManager;
final Context mContext;
- final MediaOutputController mMediaOutputController;
+ final MediaSwitchingController mMediaSwitchingController;
final BroadcastSender mBroadcastSender;
/**
@@ -212,22 +210,22 @@
@Override
public void onLayoutCompleted(RecyclerView.State state) {
super.onLayoutCompleted(state);
- mMediaOutputController.setRefreshing(false);
- mMediaOutputController.refreshDataSetIfNeeded();
+ mMediaSwitchingController.setRefreshing(false);
+ mMediaSwitchingController.refreshDataSetIfNeeded();
}
}
public MediaOutputBaseDialog(
Context context,
BroadcastSender broadcastSender,
- MediaOutputController mediaOutputController,
+ MediaSwitchingController mediaSwitchingController,
boolean includePlaybackAndAppMetadata) {
super(context, R.style.Theme_SystemUI_Dialog_Media);
// Save the context that is wrapped with our theme.
mContext = getContext();
mBroadcastSender = broadcastSender;
- mMediaOutputController = mediaOutputController;
+ mMediaSwitchingController = mediaSwitchingController;
mLayoutManager = new LayoutManagerWrapper(mContext);
mListMaxHeight = context.getResources().getDimensionPixelSize(
R.dimen.media_output_dialog_list_max_height);
@@ -279,9 +277,9 @@
// Init bottom buttons
mDoneButton.setOnClickListener(v -> dismiss());
mStopButton.setOnClickListener(v -> onStopButtonClick());
- mAppButton.setOnClickListener(mMediaOutputController::tryToLaunchMediaApplication);
+ mAppButton.setOnClickListener(mMediaSwitchingController::tryToLaunchMediaApplication);
mMediaMetadataSectionLayout.setOnClickListener(
- mMediaOutputController::tryToLaunchMediaApplication);
+ mMediaSwitchingController::tryToLaunchMediaApplication);
mDismissing = false;
}
@@ -298,10 +296,10 @@
@Override
public void start() {
- mMediaOutputController.start(this);
+ mMediaSwitchingController.start(this);
if (isBroadcastSupported() && !mIsLeBroadcastCallbackRegistered) {
- mMediaOutputController.registerLeBroadcastServiceCallback(mExecutor,
- mBroadcastCallback);
+ mMediaSwitchingController.registerLeBroadcastServiceCallback(
+ mExecutor, mBroadcastCallback);
mIsLeBroadcastCallbackRegistered = true;
}
}
@@ -311,11 +309,11 @@
// unregister broadcast callback should only depend on profile and registered flag
// rather than remote device or broadcast state
// otherwise it might have risks of leaking registered callback handle
- if (mMediaOutputController.isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) {
- mMediaOutputController.unregisterLeBroadcastServiceCallback(mBroadcastCallback);
+ if (mMediaSwitchingController.isBroadcastSupported() && mIsLeBroadcastCallbackRegistered) {
+ mMediaSwitchingController.unregisterLeBroadcastServiceCallback(mBroadcastCallback);
mIsLeBroadcastCallbackRegistered = false;
}
- mMediaOutputController.stop();
+ mMediaSwitchingController.stop();
}
@VisibleForTesting
@@ -326,18 +324,17 @@
void refresh(boolean deviceSetChanged) {
// TODO(287191450): remove binder calls in this method from the UI thread.
// If the dialog is going away or is already refreshing, do nothing.
- if (mDismissing || mMediaOutputController.isRefreshing()) {
+ if (mDismissing || mMediaSwitchingController.isRefreshing()) {
return;
}
- mMediaOutputController.setRefreshing(true);
+ mMediaSwitchingController.setRefreshing(true);
// Update header icon
final int iconRes = getHeaderIconRes();
final IconCompat headerIcon = getHeaderIcon();
final IconCompat appSourceIcon = getAppSourceIcon();
boolean colorSetUpdated = false;
mCastAppLayout.setVisibility(
- mMediaOutputController.shouldShowLaunchSection()
- ? View.VISIBLE : View.GONE);
+ mMediaSwitchingController.shouldShowLaunchSection() ? View.VISIBLE : View.GONE);
if (iconRes != 0) {
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageResource(iconRes);
@@ -371,10 +368,10 @@
mAppResourceIcon.setVisibility(View.GONE);
} else if (appSourceIcon != null) {
Icon appIcon = appSourceIcon.toIcon(mContext);
- mAppResourceIcon.setColorFilter(mMediaOutputController.getColorItemContent());
+ mAppResourceIcon.setColorFilter(mMediaSwitchingController.getColorItemContent());
mAppResourceIcon.setImageIcon(appIcon);
} else {
- Drawable appIconDrawable = mMediaOutputController.getAppSourceIconFromPackage();
+ Drawable appIconDrawable = mMediaSwitchingController.getAppSourceIconFromPackage();
if (appIconDrawable != null) {
mAppResourceIcon.setImageDrawable(appIconDrawable);
} else {
@@ -387,7 +384,7 @@
R.dimen.media_output_dialog_header_icon_padding);
mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
}
- mAppButton.setText(mMediaOutputController.getAppSourceName());
+ mAppButton.setText(mMediaSwitchingController.getAppSourceName());
if (!mIncludePlaybackAndAppMetadata) {
mHeaderTitle.setVisibility(View.GONE);
@@ -424,23 +421,26 @@
mAdapter.updateItems();
}
} else {
- mMediaOutputController.setRefreshing(false);
- mMediaOutputController.refreshDataSetIfNeeded();
+ mMediaSwitchingController.setRefreshing(false);
+ mMediaSwitchingController.refreshDataSetIfNeeded();
}
}
private void updateButtonBackgroundColorFilter() {
- ColorFilter buttonColorFilter = new PorterDuffColorFilter(
- mMediaOutputController.getColorButtonBackground(),
- PorterDuff.Mode.SRC_IN);
+ ColorFilter buttonColorFilter =
+ new PorterDuffColorFilter(
+ mMediaSwitchingController.getColorButtonBackground(),
+ PorterDuff.Mode.SRC_IN);
mDoneButton.getBackground().setColorFilter(buttonColorFilter);
mStopButton.getBackground().setColorFilter(buttonColorFilter);
- mDoneButton.setTextColor(mMediaOutputController.getColorPositiveButtonText());
+ mDoneButton.setTextColor(mMediaSwitchingController.getColorPositiveButtonText());
}
private void updateDialogBackgroundColor() {
- getDialogView().getBackground().setTint(mMediaOutputController.getColorDialogBackground());
- mDeviceListLayout.setBackgroundColor(mMediaOutputController.getColorDialogBackground());
+ getDialogView()
+ .getBackground()
+ .setTint(mMediaSwitchingController.getColorDialogBackground());
+ mDeviceListLayout.setBackgroundColor(mMediaSwitchingController.getColorDialogBackground());
}
private Drawable resizeDrawable(Drawable drawable, int size) {
@@ -499,7 +499,7 @@
protected void startLeBroadcast() {
mStopButton.setText(R.string.media_output_broadcast_starting);
mStopButton.setEnabled(false);
- if (!mMediaOutputController.startBluetoothLeBroadcast()) {
+ if (!mMediaSwitchingController.startBluetoothLeBroadcast()) {
// If the system can't execute "broadcast start", then UI shows the error.
handleLeBroadcastStartFailed();
}
@@ -512,9 +512,10 @@
&& sharedPref.getBoolean(PREF_IS_LE_BROADCAST_FIRST_LAUNCH, true)) {
Log.d(TAG, "PREF_IS_LE_BROADCAST_FIRST_LAUNCH: true");
- mMediaOutputController.launchLeBroadcastNotifyDialog(mDialogView,
+ mMediaSwitchingController.launchLeBroadcastNotifyDialog(
+ mDialogView,
mBroadcastSender,
- MediaOutputController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH,
+ MediaSwitchingController.BroadcastNotifyDialog.ACTION_FIRST_LAUNCH,
(d, w) -> {
startLeBroadcast();
});
@@ -527,14 +528,13 @@
}
protected void startLeBroadcastDialog() {
- mMediaOutputController.launchMediaOutputBroadcastDialog(mDialogView,
- mBroadcastSender);
+ mMediaSwitchingController.launchMediaOutputBroadcastDialog(mDialogView, mBroadcastSender);
refresh();
}
protected void stopLeBroadcast() {
mStopButton.setEnabled(false);
- if (!mMediaOutputController.stopBluetoothLeBroadcast()) {
+ if (!mMediaSwitchingController.stopBluetoothLeBroadcast()) {
// If the system can't execute "broadcast stop", then UI does refresh.
mMainThreadHandler.post(() -> refresh());
}
@@ -559,7 +559,7 @@
}
public void onStopButtonClick() {
- mMediaOutputController.releaseSession();
+ mMediaSwitchingController.releaseSession();
dismiss();
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 1e31755..9b5b872a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -235,14 +235,17 @@
}
};
- MediaOutputBroadcastDialog(Context context, boolean aboveStatusbar,
- BroadcastSender broadcastSender, MediaOutputController mediaOutputController) {
+ MediaOutputBroadcastDialog(
+ Context context,
+ boolean aboveStatusbar,
+ BroadcastSender broadcastSender,
+ MediaSwitchingController mediaSwitchingController) {
super(
context,
broadcastSender,
- mediaOutputController, /* includePlaybackAndAppMetadata */
+ mediaSwitchingController, /* includePlaybackAndAppMetadata */
true);
- mAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mAdapter = new MediaOutputAdapter(mMediaSwitchingController);
// TODO(b/226710953): Move the part to MediaOutputBaseDialog for every class
// that extends MediaOutputBaseDialog
if (!aboveStatusbar) {
@@ -262,8 +265,8 @@
super.start();
if (!mIsLeBroadcastAssistantCallbackRegistered) {
mIsLeBroadcastAssistantCallbackRegistered = true;
- mMediaOutputController.registerLeBroadcastAssistantServiceCallback(mExecutor,
- mBroadcastAssistantCallback);
+ mMediaSwitchingController.registerLeBroadcastAssistantServiceCallback(
+ mExecutor, mBroadcastAssistantCallback);
}
/* Add local source broadcast to connected capable devices that may be possible receivers
* of stream.
@@ -276,7 +279,7 @@
super.stop();
if (mIsLeBroadcastAssistantCallbackRegistered) {
mIsLeBroadcastAssistantCallbackRegistered = false;
- mMediaOutputController.unregisterLeBroadcastAssistantServiceCallback(
+ mMediaSwitchingController.unregisterLeBroadcastAssistantServiceCallback(
mBroadcastAssistantCallback);
}
}
@@ -288,7 +291,7 @@
@Override
IconCompat getHeaderIcon() {
- return mMediaOutputController.getHeaderIcon();
+ return mMediaSwitchingController.getHeaderIcon();
}
@Override
@@ -299,17 +302,17 @@
@Override
CharSequence getHeaderText() {
- return mMediaOutputController.getHeaderTitle();
+ return mMediaSwitchingController.getHeaderTitle();
}
@Override
CharSequence getHeaderSubtitle() {
- return mMediaOutputController.getHeaderSubTitle();
+ return mMediaSwitchingController.getHeaderSubTitle();
}
@Override
IconCompat getAppSourceIcon() {
- return mMediaOutputController.getNotificationSmallIcon();
+ return mMediaSwitchingController.getNotificationSmallIcon();
}
@Override
@@ -319,16 +322,16 @@
@Override
public void onStopButtonClick() {
- mMediaOutputController.stopBluetoothLeBroadcast();
+ mMediaSwitchingController.stopBluetoothLeBroadcast();
dismiss();
}
private String getBroadcastMetadataInfo(int metadata) {
switch (metadata) {
case METADATA_BROADCAST_NAME:
- return mMediaOutputController.getBroadcastName();
+ return mMediaSwitchingController.getBroadcastName();
case METADATA_BROADCAST_CODE:
- return mMediaOutputController.getBroadcastCode();
+ return mMediaSwitchingController.getBroadcastCode();
default:
return "";
}
@@ -342,13 +345,15 @@
mBroadcastQrCodeView = getDialogView().requireViewById(R.id.qrcode_view);
mBroadcastNotify = getDialogView().requireViewById(R.id.broadcast_info);
- mBroadcastNotify.setOnClickListener(v -> {
- mMediaOutputController.launchLeBroadcastNotifyDialog(
- /* view= */ null,
- /* broadcastSender= */ null,
- MediaOutputController.BroadcastNotifyDialog.ACTION_BROADCAST_INFO_ICON,
- /* onClickListener= */ null);
- });
+ mBroadcastNotify.setOnClickListener(
+ v -> {
+ mMediaSwitchingController.launchLeBroadcastNotifyDialog(
+ /* mediaOutputDialog= */ null,
+ /* broadcastSender= */ null,
+ MediaSwitchingController.BroadcastNotifyDialog
+ .ACTION_BROADCAST_INFO_ICON,
+ /* listener= */ null);
+ });
mBroadcastName = getDialogView().requireViewById(R.id.broadcast_name_summary);
mBroadcastNameEdit = getDialogView().requireViewById(R.id.broadcast_name_edit);
mBroadcastNameEdit.setOnClickListener(v -> {
@@ -409,16 +414,16 @@
return;
}
- for (BluetoothDevice sink : mMediaOutputController.getConnectedBroadcastSinkDevices()) {
+ for (BluetoothDevice sink : mMediaSwitchingController.getConnectedBroadcastSinkDevices()) {
Log.d(TAG, "The broadcastMetadata broadcastId: " + broadcastMetadata.getBroadcastId()
+ ", the device: " + sink.getAnonymizedAddress());
- if (mMediaOutputController.isThereAnyBroadcastSourceIntoSinkDevice(sink)) {
+ if (mMediaSwitchingController.isThereAnyBroadcastSourceIntoSinkDevice(sink)) {
Log.d(TAG, "The sink device has the broadcast source now.");
return;
}
- if (!mMediaOutputController.addSourceIntoSinkDeviceWithBluetoothLeAssistant(sink,
- broadcastMetadata, /*isGroupOp=*/ false)) {
+ if (!mMediaSwitchingController.addSourceIntoSinkDeviceWithBluetoothLeAssistant(
+ sink, broadcastMetadata, /* isGroupOp= */ false)) {
Log.e(TAG, "Error: Source add failed");
}
}
@@ -457,11 +462,11 @@
}
private String getLocalBroadcastMetadataQrCodeString() {
- return mMediaOutputController.getLocalBroadcastMetadataQrCodeString();
+ return mMediaSwitchingController.getLocalBroadcastMetadataQrCodeString();
}
private BluetoothLeBroadcastMetadata getBroadcastMetadata() {
- return mMediaOutputController.getBroadcastMetadata();
+ return mMediaSwitchingController.getBroadcastMetadata();
}
@VisibleForTesting
@@ -476,8 +481,8 @@
* stopped then used the new Broadcast code to start the Broadcast.
*/
mIsStopbyUpdateBroadcastCode = true;
- mMediaOutputController.setBroadcastCode(updatedString);
- if (!mMediaOutputController.stopBluetoothLeBroadcast()) {
+ mMediaSwitchingController.setBroadcastCode(updatedString);
+ if (!mMediaSwitchingController.stopBluetoothLeBroadcast()) {
handleLeBroadcastStopFailed();
return;
}
@@ -485,8 +490,8 @@
/* If the user wants to update the Broadcast Name, we don't need to stop the Broadcast
* session. Only use the new Broadcast name to update the broadcast session.
*/
- mMediaOutputController.setBroadcastName(updatedString);
- if (!mMediaOutputController.updateBluetoothLeBroadcast()) {
+ mMediaSwitchingController.setBroadcastName(updatedString);
+ if (!mMediaSwitchingController.updateBluetoothLeBroadcast()) {
handleLeBroadcastUpdateFailed();
}
}
@@ -496,12 +501,13 @@
public boolean isBroadcastSupported() {
if (!legacyLeAudioSharing()) return false;
boolean isBluetoothLeDevice = false;
- if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
- isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
- mMediaOutputController.getCurrentConnectedMediaDevice());
+ if (mMediaSwitchingController.getCurrentConnectedMediaDevice() != null) {
+ isBluetoothLeDevice =
+ mMediaSwitchingController.isBluetoothLeDevice(
+ mMediaSwitchingController.getCurrentConnectedMediaDevice());
}
- return mMediaOutputController.isBroadcastSupported() && isBluetoothLeDevice;
+ return mMediaSwitchingController.isBroadcastSupported() && isBluetoothLeDevice;
}
@Override
@@ -515,7 +521,7 @@
@Override
public void handleLeBroadcastStartFailed() {
- mMediaOutputController.setBroadcastCode(mCurrentBroadcastCode);
+ mMediaSwitchingController.setBroadcastCode(mCurrentBroadcastCode);
mRetryCount++;
handleUpdateFailedUi();
@@ -538,8 +544,8 @@
@Override
public void handleLeBroadcastUpdateFailed() {
- //Change the value in shared preferences back to it original value
- mMediaOutputController.setBroadcastName(mCurrentBroadcastName);
+ // Change the value in shared preferences back to it original value
+ mMediaSwitchingController.setBroadcastName(mCurrentBroadcastName);
mRetryCount++;
handleUpdateFailedUi();
@@ -550,7 +556,7 @@
if (mIsStopbyUpdateBroadcastCode) {
mIsStopbyUpdateBroadcastCode = false;
mRetryCount = 0;
- if (!mMediaOutputController.startBluetoothLeBroadcast()) {
+ if (!mMediaSwitchingController.startBluetoothLeBroadcast()) {
handleLeBroadcastStartFailed();
return;
}
@@ -561,8 +567,8 @@
@Override
public void handleLeBroadcastStopFailed() {
- //Change the value in shared preferences back to it original value
- mMediaOutputController.setBroadcastCode(mCurrentBroadcastCode);
+ // Change the value in shared preferences back to it original value
+ mMediaSwitchingController.setBroadcastCode(mCurrentBroadcastCode);
mRetryCount++;
handleUpdateFailedUi();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
index 6ef9ea3..2e7e66f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogManager.kt
@@ -29,7 +29,7 @@
private val context: Context,
private val broadcastSender: BroadcastSender,
private val dialogTransitionAnimator: DialogTransitionAnimator,
- private val mediaOutputControllerFactory: MediaOutputController.Factory
+ private val mediaSwitchingControllerFactory: MediaSwitchingController.Factory
) {
var mediaOutputBroadcastDialog: MediaOutputBroadcastDialog? = null
@@ -41,7 +41,7 @@
// TODO: b/321969740 - Populate the userHandle parameter. The user handle is necessary to
// disambiguate the same package running on different users.
val controller =
- mediaOutputControllerFactory.create(
+ mediaSwitchingControllerFactory.create(
packageName,
/* userHandle= */ null,
/* token */ null,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index eb6a320..c9af7b3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -46,14 +46,14 @@
Context context,
boolean aboveStatusbar,
BroadcastSender broadcastSender,
- MediaOutputController mediaOutputController,
+ MediaSwitchingController mediaSwitchingController,
DialogTransitionAnimator dialogTransitionAnimator,
UiEventLogger uiEventLogger,
boolean includePlaybackAndAppMetadata) {
- super(context, broadcastSender, mediaOutputController, includePlaybackAndAppMetadata);
+ super(context, broadcastSender, mediaSwitchingController, includePlaybackAndAppMetadata);
mDialogTransitionAnimator = dialogTransitionAnimator;
mUiEventLogger = uiEventLogger;
- mAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mAdapter = new MediaOutputAdapter(mMediaSwitchingController);
if (!aboveStatusbar) {
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
}
@@ -72,7 +72,7 @@
@Override
IconCompat getHeaderIcon() {
- return mMediaOutputController.getHeaderIcon();
+ return mMediaSwitchingController.getHeaderIcon();
}
@Override
@@ -83,27 +83,29 @@
@Override
CharSequence getHeaderText() {
- return mMediaOutputController.getHeaderTitle();
+ return mMediaSwitchingController.getHeaderTitle();
}
@Override
CharSequence getHeaderSubtitle() {
- return mMediaOutputController.getHeaderSubTitle();
+ return mMediaSwitchingController.getHeaderSubTitle();
}
@Override
IconCompat getAppSourceIcon() {
- return mMediaOutputController.getNotificationSmallIcon();
+ return mMediaSwitchingController.getNotificationSmallIcon();
}
@Override
int getStopButtonVisibility() {
boolean isActiveRemoteDevice = false;
- if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
- isActiveRemoteDevice = mMediaOutputController.isActiveRemoteDevice(
- mMediaOutputController.getCurrentConnectedMediaDevice());
+ if (mMediaSwitchingController.getCurrentConnectedMediaDevice() != null) {
+ isActiveRemoteDevice =
+ mMediaSwitchingController.isActiveRemoteDevice(
+ mMediaSwitchingController.getCurrentConnectedMediaDevice());
}
- boolean showBroadcastButton = isBroadcastSupported() && mMediaOutputController.isPlaying();
+ boolean showBroadcastButton =
+ isBroadcastSupported() && mMediaSwitchingController.isPlaying();
return (isActiveRemoteDevice || showBroadcastButton) ? View.VISIBLE : View.GONE;
}
@@ -115,13 +117,14 @@
boolean isBroadcastEnabled = false;
if (FeatureFlagUtils.isEnabled(mContext,
FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST)) {
- if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
- isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
- mMediaOutputController.getCurrentConnectedMediaDevice());
+ if (mMediaSwitchingController.getCurrentConnectedMediaDevice() != null) {
+ isBluetoothLeDevice =
+ mMediaSwitchingController.isBluetoothLeDevice(
+ mMediaSwitchingController.getCurrentConnectedMediaDevice());
// if broadcast is active, broadcast should be considered as supported
// there could be a valid case that broadcast is ongoing
// without active LEA device connected
- isBroadcastEnabled = mMediaOutputController.isBluetoothLeBroadcastEnabled();
+ isBroadcastEnabled = mMediaSwitchingController.isBluetoothLeBroadcastEnabled();
}
} else {
// To decouple LE Audio Broadcast and Unicast, it always displays the button when there
@@ -129,15 +132,16 @@
isBluetoothLeDevice = true;
}
- return mMediaOutputController.isBroadcastSupported()
+ return mMediaSwitchingController.isBroadcastSupported()
&& (isBluetoothLeDevice || isBroadcastEnabled);
}
@Override
public CharSequence getStopButtonText() {
int resId = R.string.media_output_dialog_button_stop_casting;
- if (isBroadcastSupported() && mMediaOutputController.isPlaying()
- && !mMediaOutputController.isBluetoothLeBroadcastEnabled()) {
+ if (isBroadcastSupported()
+ && mMediaSwitchingController.isPlaying()
+ && !mMediaSwitchingController.isBluetoothLeBroadcastEnabled()) {
resId = R.string.media_output_broadcast;
}
return mContext.getText(resId);
@@ -145,8 +149,8 @@
@Override
public void onStopButtonClick() {
- if (isBroadcastSupported() && mMediaOutputController.isPlaying()) {
- if (!mMediaOutputController.isBluetoothLeBroadcastEnabled()) {
+ if (isBroadcastSupported() && mMediaSwitchingController.isPlaying()) {
+ if (!mMediaSwitchingController.isBluetoothLeBroadcastEnabled()) {
if (startLeBroadcastDialogForFirstTime()) {
return;
}
@@ -155,7 +159,7 @@
stopLeBroadcast();
}
} else {
- mMediaOutputController.releaseSession();
+ mMediaSwitchingController.releaseSession();
mDialogTransitionAnimator.disableAllCurrentDialogsExitAnimations();
dismiss();
}
@@ -163,8 +167,9 @@
@Override
public int getBroadcastIconVisibility() {
- return (isBroadcastSupported() && mMediaOutputController.isBluetoothLeBroadcastEnabled())
- ? View.VISIBLE : View.GONE;
+ return (isBroadcastSupported() && mMediaSwitchingController.isBluetoothLeBroadcastEnabled())
+ ? View.VISIBLE
+ : View.GONE;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
index 47e0691..4e9451a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogManager.kt
@@ -35,7 +35,7 @@
private val broadcastSender: BroadcastSender,
private val uiEventLogger: UiEventLogger,
private val dialogTransitionAnimator: DialogTransitionAnimator,
- private val mediaOutputControllerFactory: MediaOutputController.Factory,
+ private val mediaSwitchingControllerFactory: MediaSwitchingController.Factory,
) {
companion object {
const val INTERACTION_JANK_TAG = "media_output"
@@ -118,7 +118,7 @@
// Dismiss the previous dialog, if any.
mediaOutputDialog?.dismiss()
- val controller = mediaOutputControllerFactory.create(packageName, userHandle, token)
+ val controller = mediaSwitchingControllerFactory.create(packageName, userHandle, token)
val mediaOutputDialog =
MediaOutputDialog(
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
rename to packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
index 875e505..2cbc7575 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
@@ -77,6 +77,7 @@
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.InfoMediaManager;
+import com.android.settingslib.media.InputRouteManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.settingslib.media.flags.Flags;
@@ -116,12 +117,13 @@
import java.util.stream.Collectors;
/**
- * Controller for media output dialog
+ * Controller for a dialog that allows users to switch media output and input devices, control
+ * volume, connect to new devices, etc.
*/
-public class MediaOutputController implements LocalMediaManager.DeviceCallback,
- INearbyMediaDevicesUpdateCallback {
+public class MediaSwitchingController
+ implements LocalMediaManager.DeviceCallback, INearbyMediaDevicesUpdateCallback {
- private static final String TAG = "MediaOutputController";
+ private static final String TAG = "MediaSwitchingController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String PAGE_CONNECTED_DEVICES_KEY =
"top_level_connected_devices";
@@ -137,10 +139,12 @@
private final DialogTransitionAnimator mDialogTransitionAnimator;
private final CommonNotifCollection mNotifCollection;
protected final Object mMediaDevicesLock = new Object();
+ protected final Object mInputMediaDevicesLock = new Object();
@VisibleForTesting
final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
final List<MediaDevice> mCachedMediaDevices = new CopyOnWriteArrayList<>();
- private final List<MediaItem> mMediaItemList = new CopyOnWriteArrayList<>();
+ private final List<MediaItem> mOutputMediaItemList = new CopyOnWriteArrayList<>();
+ private final List<MediaItem> mInputMediaItemList = new CopyOnWriteArrayList<>();
private final AudioManager mAudioManager;
private final PowerExemptionManager mPowerExemptionManager;
private final KeyguardManager mKeyGuardManager;
@@ -153,6 +157,7 @@
@VisibleForTesting
boolean mNeedRefresh = false;
private MediaController mMediaController;
+ private InputRouteManager mInputRouteManager;
@VisibleForTesting
Callback mCallback;
@VisibleForTesting
@@ -181,8 +186,20 @@
ACTION_BROADCAST_INFO_ICON
}
+ @VisibleForTesting
+ final InputRouteManager.InputDeviceCallback mInputDeviceCallback =
+ new InputRouteManager.InputDeviceCallback() {
+ @Override
+ public void onInputDeviceListUpdated(@NonNull List<MediaDevice> devices) {
+ synchronized (mInputMediaDevicesLock) {
+ buildInputMediaItems(devices);
+ mCallback.onDeviceListChanged();
+ }
+ }
+ };
+
@AssistedInject
- public MediaOutputController(
+ public MediaSwitchingController(
Context context,
@Assisted String packageName,
@Assisted @Nullable UserHandle userHandle,
@@ -241,19 +258,23 @@
R.dimen.media_output_dialog_default_margin_end);
mItemMarginEndSelectable = (int) mContext.getResources().getDimension(
R.dimen.media_output_dialog_selectable_margin_end);
+
+ if (enableInputRouting()) {
+ mInputRouteManager = new InputRouteManager(mContext, audioManager);
+ }
}
@AssistedFactory
public interface Factory {
- /** Construct a MediaOutputController */
- MediaOutputController create(
+ /** Construct a MediaSwitchingController */
+ MediaSwitchingController create(
String packageName, UserHandle userHandle, MediaSession.Token token);
}
protected void start(@NonNull Callback cb) {
synchronized (mMediaDevicesLock) {
mCachedMediaDevices.clear();
- mMediaItemList.clear();
+ mOutputMediaItemList.clear();
}
mNearbyDeviceInfoMap.clear();
if (mNearbyMediaDevicesManager != null) {
@@ -277,6 +298,10 @@
mCallback = cb;
mLocalMediaManager.registerCallback(this);
mLocalMediaManager.startScan();
+
+ if (enableInputRouting()) {
+ mInputRouteManager.registerCallback(mInputDeviceCallback);
+ }
}
boolean shouldShowLaunchSection() {
@@ -300,12 +325,19 @@
mLocalMediaManager.stopScan();
synchronized (mMediaDevicesLock) {
mCachedMediaDevices.clear();
- mMediaItemList.clear();
+ mOutputMediaItemList.clear();
}
if (mNearbyMediaDevicesManager != null) {
mNearbyMediaDevicesManager.unregisterNearbyDevicesCallback(this);
}
mNearbyDeviceInfoMap.clear();
+
+ if (enableInputRouting()) {
+ mInputRouteManager.unregisterCallback(mInputDeviceCallback);
+ synchronized (mInputMediaDevicesLock) {
+ mInputMediaItemList.clear();
+ }
+ }
}
private MediaController getMediaController() {
@@ -335,7 +367,7 @@
@Override
public void onDeviceListUpdate(List<MediaDevice> devices) {
- boolean isListEmpty = mMediaItemList.isEmpty();
+ boolean isListEmpty = mOutputMediaItemList.isEmpty();
if (isListEmpty || !mIsRefreshing) {
buildMediaItems(devices);
mCallback.onDeviceListChanged();
@@ -352,7 +384,8 @@
public void onSelectedDeviceStateChanged(MediaDevice device,
@LocalMediaManager.MediaDeviceState int state) {
mCallback.onRouteChanged();
- mMetricLogger.logOutputItemSuccess(device.toString(), new ArrayList<>(mMediaItemList));
+ mMetricLogger.logOutputItemSuccess(
+ device.toString(), new ArrayList<>(mOutputMediaItemList));
}
@Override
@@ -363,7 +396,7 @@
@Override
public void onRequestFailed(int reason) {
mCallback.onRouteChanged();
- mMetricLogger.logOutputItemFailure(new ArrayList<>(mMediaItemList), reason);
+ mMetricLogger.logOutputItemFailure(new ArrayList<>(mOutputMediaItemList), reason);
}
/**
@@ -382,7 +415,7 @@
}
try {
synchronized (mMediaDevicesLock) {
- mMediaItemList.removeIf((MediaItem::isMutingExpectedDevice));
+ mOutputMediaItemList.removeIf((MediaItem::isMutingExpectedDevice));
}
mAudioManager.cancelMuteAwaitConnection(mAudioManager.getMutingExpectedDevice());
} catch (Exception e) {
@@ -638,9 +671,9 @@
private void buildMediaItems(List<MediaDevice> devices) {
synchronized (mMediaDevicesLock) {
- List<MediaItem> updatedMediaItems = buildMediaItems(mMediaItemList, devices);
- mMediaItemList.clear();
- mMediaItemList.addAll(updatedMediaItems);
+ List<MediaItem> updatedMediaItems = buildMediaItems(mOutputMediaItemList, devices);
+ mOutputMediaItemList.clear();
+ mOutputMediaItemList.addAll(updatedMediaItems);
}
}
@@ -714,6 +747,19 @@
}
}
+ private boolean enableInputRouting() {
+ return com.android.media.flags.Flags.enableAudioInputDeviceRoutingAndVolumeControl();
+ }
+
+ private void buildInputMediaItems(List<MediaDevice> devices) {
+ synchronized (mInputMediaDevicesLock) {
+ List<MediaItem> updatedInputMediaItems =
+ devices.stream().map(MediaItem::createDeviceMediaItem).toList();
+ mInputMediaItemList.clear();
+ mInputMediaItemList.addAll(updatedInputMediaItems);
+ }
+ }
+
/**
* Initial categorization of current devices, will not be called for updates to the devices
* list.
@@ -778,7 +824,6 @@
mediaDevice.setRangeZone(mNearbyDeviceInfoMap.get(mediaDevice.getId()));
}
}
-
}
boolean isCurrentConnectedDeviceRemote() {
@@ -837,8 +882,31 @@
});
}
+ private void addInputDevices(List<MediaItem> mediaItems) {
+ mediaItems.add(
+ MediaItem.createGroupDividerMediaItem(
+ mContext.getString(R.string.media_input_group_title)));
+ mediaItems.addAll(mInputMediaItemList);
+ }
+
+ private void addOutputDevices(List<MediaItem> mediaItems) {
+ mediaItems.add(
+ MediaItem.createGroupDividerMediaItem(
+ mContext.getString(R.string.media_output_group_title)));
+ mediaItems.addAll(mOutputMediaItemList);
+ }
+
public List<MediaItem> getMediaItemList() {
- return mMediaItemList;
+ // If input routing is not enabled, only return output media items.
+ if (!enableInputRouting()) {
+ return mOutputMediaItemList;
+ }
+
+ // If input routing is enabled, return both output and input media items.
+ List<MediaItem> mediaItems = new ArrayList<>();
+ addOutputDevices(mediaItems);
+ addInputDevices(mediaItems);
+ return mediaItems;
}
public MediaDevice getCurrentConnectedMediaDevice() {
@@ -921,7 +989,7 @@
public boolean isAnyDeviceTransferring() {
synchronized (mMediaDevicesLock) {
- for (MediaItem mediaItem : mMediaItemList) {
+ for (MediaItem mediaItem : mOutputMediaItemList) {
if (mediaItem.getMediaDevice().isPresent()
&& mediaItem.getMediaDevice().get().getState()
== LocalMediaManager.MediaDeviceState.STATE_CONNECTING) {
@@ -986,8 +1054,8 @@
}
void launchMediaOutputBroadcastDialog(View mediaOutputDialog, BroadcastSender broadcastSender) {
- MediaOutputController controller =
- new MediaOutputController(
+ MediaSwitchingController controller =
+ new MediaSwitchingController(
mContext,
mPackageName,
mUserHandle,
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index db5a545c..0d748a1 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -17,11 +17,13 @@
package com.android.systemui.model
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING
@@ -57,12 +59,12 @@
val transitionState = sceneInteractor.get().transitionState.value
val idleTransitionStateOrNull = transitionState as? ObservableTransitionState.Idle
- val currentSceneOrNull = idleTransitionStateOrNull?.currentScene
val invisibleDueToOcclusion = occlusionInteractor.get().invisibleDueToOcclusion.value
- return currentSceneOrNull?.let { sceneKey ->
+ return idleTransitionStateOrNull?.let { idleState ->
EvaluatorByFlag[flag]?.invoke(
SceneContainerPluginState(
- scene = sceneKey,
+ scene = idleState.currentScene,
+ overlays = idleState.currentOverlays,
invisibleDueToOcclusion = invisibleDueToOcclusion,
)
)
@@ -89,10 +91,15 @@
it.invisibleDueToOcclusion -> false
it.scene == Scenes.Lockscreen -> true
it.scene == Scenes.Shade -> true
+ Overlays.NotificationsShade in it.overlays -> true
else -> false
}
},
- SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it.scene == Scenes.QuickSettings },
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED to
+ {
+ it.scene == Scenes.QuickSettings ||
+ Overlays.QuickSettingsShade in it.overlays
+ },
SYSUI_STATE_BOUNCER_SHOWING to { it.scene == Scenes.Bouncer },
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to
{
@@ -106,5 +113,9 @@
)
}
- data class SceneContainerPluginState(val scene: SceneKey, val invisibleDueToOcclusion: Boolean)
+ data class SceneContainerPluginState(
+ val scene: SceneKey,
+ val overlays: Set<OverlayKey>,
+ val invisibleDueToOcclusion: Boolean,
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
similarity index 65%
rename from packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt
rename to packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
index 601fbfa..a0663d7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
@@ -14,26 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.shared
+package com.android.systemui.modes.shared
-import com.android.systemui.Flags
-import com.android.systemui.flags.FlagToken
+import android.app.Flags
import com.android.systemui.flags.RefactorFlagUtils
-/** Helper for reading or using the compose lockscreen flag state. */
+/** Helper for reading or using the modes ui flag state. */
@Suppress("NOTHING_TO_INLINE")
-object ComposeLockscreen {
- /** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_COMPOSE_LOCKSCREEN
-
- /** A token used for dependency declaration */
- val token: FlagToken
- get() = FlagToken(FLAG_NAME, isEnabled)
-
+object ModesUi {
/** Is the refactor enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.composeLockscreen()
+ get() = Flags.modesApi() && Flags.modesUi()
/**
* Called to ensure code is only run when the flag is enabled. This protects users from the
@@ -42,12 +34,21 @@
*/
@JvmStatic
inline fun isUnexpectedlyInLegacyMode() =
- RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, Flags.FLAG_MODES_UI)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is not enabled to ensure that the refactor author catches issues in testing.
+ * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
+ */
+ @JvmStatic
+ inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, Flags.FLAG_MODES_UI)
/**
* Called to ensure code is only run when the flag is disabled. This will throw an exception if
* the flag is enabled to ensure that the refactor author catches issues in testing.
*/
@JvmStatic
- inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+ inline fun assertInLegacyMode() =
+ RefactorFlagUtils.assertInLegacyMode(isEnabled, Flags.FLAG_MODES_UI)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUiIcons.kt
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt
copy to packages/SystemUI/src/com/android/systemui/modes/shared/ModesUiIcons.kt
index 601fbfa..032b0ac 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/ComposeLockscreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUiIcons.kt
@@ -14,26 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.keyguard.shared
+package com.android.systemui.modes.shared
-import com.android.systemui.Flags
-import com.android.systemui.flags.FlagToken
+import android.app.Flags
import com.android.systemui.flags.RefactorFlagUtils
-/** Helper for reading or using the compose lockscreen flag state. */
+/** Helper for reading or using the modes ui icons flag state. */
@Suppress("NOTHING_TO_INLINE")
-object ComposeLockscreen {
- /** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_COMPOSE_LOCKSCREEN
-
- /** A token used for dependency declaration */
- val token: FlagToken
- get() = FlagToken(FLAG_NAME, isEnabled)
-
+object ModesUiIcons {
/** Is the refactor enabled */
@JvmStatic
inline val isEnabled
- get() = Flags.composeLockscreen()
+ get() = ModesUi.isEnabled && Flags.modesUiIcons()
/**
* Called to ensure code is only run when the flag is enabled. This protects users from the
@@ -42,12 +34,22 @@
*/
@JvmStatic
inline fun isUnexpectedlyInLegacyMode() =
- RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, Flags.FLAG_MODES_UI_ICONS)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is not enabled to ensure that the refactor author catches issues in testing.
+ * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
+ */
+ @JvmStatic
+ inline fun assertInNewMode() =
+ RefactorFlagUtils.assertInNewMode(isEnabled, Flags.FLAG_MODES_UI_ICONS)
/**
* Called to ensure code is only run when the flag is disabled. This will throw an exception if
* the flag is enabled to ensure that the refactor author catches issues in testing.
*/
@JvmStatic
- inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+ inline fun assertInLegacyMode() =
+ RefactorFlagUtils.assertInLegacyMode(isEnabled, Flags.FLAG_MODES_UI_ICONS)
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
index 54a59f30..44460ed 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt
@@ -19,11 +19,15 @@
import android.app.role.RoleManager
import android.content.Context
import android.content.pm.UserInfo
+import android.hardware.input.InputManager
+import android.hardware.input.KeyGestureEvent
+import android.os.IBinder
import android.os.UserHandle
import android.view.KeyEvent
import android.view.KeyEvent.KEYCODE_N
import android.view.KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL
import android.view.ViewConfiguration
+import com.android.hardware.input.Flags.useKeyGestureEventHandler
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.dagger.qualifiers.Background
@@ -47,6 +51,7 @@
private val optionalBubbles: Optional<Bubbles>,
private val userTracker: UserTracker,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val inputManager: InputManager,
@Background private val backgroundExecutor: Executor,
@NoteTaskEnabledKey private val isEnabled: Boolean,
) {
@@ -59,6 +64,7 @@
if (!isEnabled || optionalBubbles.isEmpty) return
initializeHandleSystemKey()
+ initializeKeyGestureEventHandler()
initializeOnRoleHoldersChanged()
initializeOnUserUnlocked()
initializeUserTracker()
@@ -73,6 +79,16 @@
}
/**
+ * Initializes a [InputManager.KeyGestureEventHandler] which will handle shortcuts for opening
+ * the notes role via [NoteTaskController].
+ */
+ private fun initializeKeyGestureEventHandler() {
+ if (useKeyGestureEventHandler()) {
+ inputManager.registerKeyGestureEventHandler(callbacks)
+ }
+ }
+
+ /**
* Initializes the [RoleManager] role holder changed listener to ensure [NoteTaskController]
* will always update whenever the role holder app changes. Keep in mind that a role may change
* by direct user interaction (i.e., user goes to settings and change it) or by indirect
@@ -110,7 +126,8 @@
KeyguardUpdateMonitorCallback(),
CommandQueue.Callbacks,
UserTracker.Callback,
- OnRoleHoldersChangedListener {
+ OnRoleHoldersChangedListener,
+ InputManager.KeyGestureEventHandler {
override fun handleSystemKey(key: KeyEvent) {
key.toNoteTaskEntryPointOrNull()?.let(controller::showNoteTask)
@@ -131,6 +148,17 @@
override fun onProfilesChanged(profiles: List<UserInfo>) {
controller.updateNoteTaskForCurrentUserAndManagedProfiles()
}
+
+ override fun handleKeyGestureEvent(
+ event: KeyGestureEvent,
+ focusedToken: IBinder?
+ ): Boolean {
+ return [email protected](event)
+ }
+
+ override fun isKeyGestureSupported(gestureType: Int): Boolean {
+ return [email protected](gestureType);
+ }
}
/**
@@ -171,6 +199,24 @@
return !isMultiPress && !isLongPress
}
+ private fun handleKeyGestureEvent(event: KeyGestureEvent): Boolean {
+ // This method is on input hot path and should be kept lightweight. Shift all complex
+ // processing onto background executor wherever possible.
+ if (event.keyGestureType != KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES) {
+ return false
+ }
+ debugLog {
+ "handleKeyGestureEvent: Received OPEN_NOTES gesture event from keycodes: " +
+ event.keycodes.contentToString()
+ }
+ backgroundExecutor.execute { controller.showNoteTask(KEYBOARD_SHORTCUT) }
+ return true
+ }
+
+ private fun isKeyGestureSupported(gestureType: Int): Boolean {
+ return gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
+ }
+
companion object {
val MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout().toLong()
val LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout().toLong()
diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
index b6868c1..63bfbd1 100644
--- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayActionsViewModel.kt
@@ -18,9 +18,13 @@
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
+import com.android.compose.animation.scene.UserActionResult.HideOverlay
+import com.android.compose.animation.scene.UserActionResult.ReplaceByOverlay
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -32,8 +36,10 @@
override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
setActions(
mapOf(
- Swipe.Up to UserActionResult.HideOverlay(Overlays.NotificationsShade),
- Back to UserActionResult.HideOverlay(Overlays.NotificationsShade),
+ Swipe.Up to HideOverlay(Overlays.NotificationsShade),
+ Back to HideOverlay(Overlays.NotificationsShade),
+ Swipe(direction = SwipeDirection.Down, fromSource = SceneContainerEdge.TopRight) to
+ ReplaceByOverlay(Overlays.QuickSettingsShade),
)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
index 66f020f..75140be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
+++ b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
@@ -1,28 +1,12 @@
{
"presubmit": [
{
- "name": "CtsTileServiceTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTileServiceTestCases"
}
],
"postsubmit": [
{
- "name": "QuickSettingsDeviceResetTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "QuickSettingsDeviceResetTests"
}
]
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index c2f1c3d..af167d4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -158,7 +158,7 @@
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
+ savedInstanceState: Bundle?,
): View {
val context = inflater.context
return ComposeView(context).apply {
@@ -181,7 +181,7 @@
notificationScrimClippingParams.bottom,
notificationScrimClippingParams.radius,
)
- }
+ },
) {
AnimatedContent(targetState = qsState) {
when (it) {
@@ -272,7 +272,7 @@
qsExpansionFraction: Float,
panelExpansionFraction: Float,
headerTranslation: Float,
- squishinessFraction: Float
+ squishinessFraction: Float,
) {
viewModel.qsExpansionValue = qsExpansionFraction
viewModel.panelExpansionFractionValue = panelExpansionFraction
@@ -318,12 +318,12 @@
override fun setTransitionToFullShadeProgress(
isTransitioningToFullShade: Boolean,
qsTransitionFraction: Float,
- qsSquishinessFraction: Float
+ qsSquishinessFraction: Float,
) {
super.setTransitionToFullShadeProgress(
isTransitioningToFullShade,
qsTransitionFraction,
- qsSquishinessFraction
+ qsSquishinessFraction,
)
}
@@ -334,7 +334,7 @@
bottom: Int,
cornerRadius: Int,
visible: Boolean,
- fullWidth: Boolean
+ fullWidth: Boolean,
) {
notificationScrimClippingParams.isEnabled = visible
notificationScrimClippingParams.top = top
@@ -402,7 +402,7 @@
launch {
setListenerJob(
heightListener,
- viewModel.containerViewModel.editModeViewModel.isEditing
+ viewModel.containerViewModel.editModeViewModel.isEditing,
) {
onQsHeightChanged()
}
@@ -410,7 +410,7 @@
launch {
setListenerJob(
qsContainerController,
- viewModel.containerViewModel.editModeViewModel.isEditing
+ viewModel.containerViewModel.editModeViewModel.isEditing,
) {
setCustomizerShowing(it)
}
@@ -422,6 +422,7 @@
@Composable
private fun QuickQuickSettingsElement() {
val qqsPadding by viewModel.qqsHeaderHeight.collectAsStateWithLifecycle()
+ val bottomPadding = dimensionResource(id = R.dimen.qqs_layout_padding_bottom)
DisposableEffect(Unit) {
qqsVisible.value = true
@@ -441,7 +442,7 @@
)
}
.onSizeChanged { size -> qqsHeight.value = size.height }
- .padding(top = { qqsPadding })
+ .padding(top = { qqsPadding }, bottom = { bottomPadding.roundToPx() })
) {
val qsEnabled by viewModel.qsEnabled.collectAsStateWithLifecycle()
if (qsEnabled) {
@@ -450,7 +451,7 @@
modifier =
Modifier.collapseExpandSemanticAction(
stringResource(id = R.string.accessibility_quick_settings_expand)
- )
+ ),
)
}
}
@@ -482,7 +483,7 @@
FooterActions(
viewModel = viewModel.footerActionsViewModel,
qsVisibilityLifecycleOwner = this@QSFragmentCompose,
- modifier = Modifier.sysuiResTag("qs_footer_actions")
+ modifier = Modifier.sysuiResTag("qs_footer_actions"),
)
}
}
@@ -562,7 +563,7 @@
private suspend inline fun <Listener : Any, Data> setListenerJob(
listenerFlow: MutableStateFlow<Listener?>,
dataFlow: Flow<Data>,
- crossinline onCollect: suspend Listener.(Data) -> Unit
+ crossinline onCollect: suspend Listener.(Data) -> Unit,
) {
coroutineScope {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
index 072d322..1fe54e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
@@ -23,17 +23,14 @@
import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepositoryImpl
import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepository
import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepositoryImpl
-import com.android.systemui.qs.panels.domain.interactor.GridTypeConsistencyInteractor
-import com.android.systemui.qs.panels.domain.interactor.InfiniteGridConsistencyInteractor
-import com.android.systemui.qs.panels.domain.interactor.NoopGridConsistencyInteractor
import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType
import com.android.systemui.qs.panels.shared.model.PanelsLog
import com.android.systemui.qs.panels.ui.compose.GridLayout
-import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout
import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
import com.android.systemui.qs.panels.ui.compose.PaginatedGridLayout
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout
import com.android.systemui.qs.panels.ui.viewmodel.FixedColumnsSizeViewModel
import com.android.systemui.qs.panels.ui.viewmodel.FixedColumnsSizeViewModelImpl
import com.android.systemui.qs.panels.ui.viewmodel.IconLabelVisibilityViewModel
@@ -56,11 +53,6 @@
@Binds
fun bindGridLayoutTypeRepository(impl: GridLayoutTypeRepositoryImpl): GridLayoutTypeRepository
- @Binds
- fun bindDefaultGridConsistencyInteractor(
- impl: NoopGridConsistencyInteractor
- ): GridTypeConsistencyInteractor
-
@Binds fun bindIconTilesViewModel(impl: IconTilesViewModelImpl): IconTilesViewModel
@Binds fun bindGridSizeViewModel(impl: FixedColumnsSizeViewModelImpl): FixedColumnsSizeViewModel
@@ -74,12 +66,6 @@
@PaginatedBaseLayoutType
fun bindPaginatedBaseGridLayout(impl: InfiniteGridLayout): PaginatableGridLayout
- @Binds
- @PaginatedBaseLayoutType
- fun bindPaginatedBaseConsistencyInteractor(
- impl: NoopGridConsistencyInteractor
- ): GridTypeConsistencyInteractor
-
@Binds @Named("Default") fun bindDefaultGridLayout(impl: PaginatedGridLayout): GridLayout
companion object {
@@ -117,28 +103,5 @@
): Set<GridLayoutType> {
return entries.map { it.first }.toSet()
}
-
- @Provides
- @IntoSet
- fun provideGridConsistencyInteractor(
- consistencyInteractor: InfiniteGridConsistencyInteractor
- ): Pair<GridLayoutType, GridTypeConsistencyInteractor> {
- return Pair(InfiniteGridLayoutType, consistencyInteractor)
- }
-
- @Provides
- @IntoSet
- fun providePaginatedGridConsistencyInteractor(
- @PaginatedBaseLayoutType consistencyInteractor: GridTypeConsistencyInteractor,
- ): Pair<GridLayoutType, GridTypeConsistencyInteractor> {
- return Pair(PaginatedGridLayoutType, consistencyInteractor)
- }
-
- @Provides
- fun provideGridConsistencyInteractorMap(
- entries: Set<@JvmSuppressWildcards Pair<GridLayoutType, GridTypeConsistencyInteractor>>
- ): Map<GridLayoutType, GridTypeConsistencyInteractor> {
- return entries.toMap()
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt
deleted file mode 100644
index a2e7ea6..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.domain.interactor
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.core.LogLevel
-import com.android.systemui.qs.panels.shared.model.GridLayoutType
-import com.android.systemui.qs.panels.shared.model.PanelsLog
-import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
-
-@SysUISingleton
-class GridConsistencyInteractor
-@Inject
-constructor(
- private val gridLayoutTypeInteractor: GridLayoutTypeInteractor,
- private val currentTilesInteractor: CurrentTilesInteractor,
- private val consistencyInteractors:
- Map<GridLayoutType, @JvmSuppressWildcards GridTypeConsistencyInteractor>,
- private val defaultConsistencyInteractor: GridTypeConsistencyInteractor,
- @PanelsLog private val logBuffer: LogBuffer,
- @Application private val applicationScope: CoroutineScope,
-) {
- fun start() {
- applicationScope.launch {
- gridLayoutTypeInteractor.layout.collectLatest { type ->
- val consistencyInteractor =
- consistencyInteractors[type] ?: defaultConsistencyInteractor
- currentTilesInteractor.currentTiles
- .map { tiles -> tiles.map { it.spec } }
- .collectLatest { tiles ->
- val newTiles = consistencyInteractor.reconcileTiles(tiles)
- if (newTiles != tiles) {
- currentTilesInteractor.setTiles(newTiles)
- logChange(newTiles)
- }
- }
- }
- }
- }
-
- private fun logChange(tiles: List<TileSpec>) {
- logBuffer.log(
- LOG_BUFFER_CURRENT_TILES_CHANGE_TAG,
- LogLevel.DEBUG,
- { str1 = tiles.toString() },
- { "Tiles reordered: $str1" }
- )
- }
-
- private companion object {
- const val LOG_BUFFER_CURRENT_TILES_CHANGE_TAG = "GridConsistencyTilesChange"
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridTypeConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridTypeConsistencyInteractor.kt
deleted file mode 100644
index 4cdabae..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridTypeConsistencyInteractor.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.domain.interactor
-
-import com.android.systemui.qs.pipeline.shared.TileSpec
-
-interface GridTypeConsistencyInteractor {
- /**
- * Given a list of tiles, return the best list of the same tiles (preserving as much order as
- * possible, such that it's consistent with the current layout.
- */
- fun reconcileTiles(tiles: List<TileSpec>): List<TileSpec>
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractor.kt
deleted file mode 100644
index 874b3b0..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractor.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.domain.interactor
-
-import android.util.Log
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.panels.shared.model.SizedTile
-import com.android.systemui.qs.panels.shared.model.SizedTileImpl
-import com.android.systemui.qs.panels.shared.model.TileRow
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import javax.inject.Inject
-
-@SysUISingleton
-class InfiniteGridConsistencyInteractor
-@Inject
-constructor(
- private val iconTilesInteractor: IconTilesInteractor,
- private val gridSizeInteractor: FixedColumnsSizeInteractor
-) : GridTypeConsistencyInteractor {
-
- /**
- * Tries to fill in every columns of all rows (except the last row), potentially reordering
- * tiles.
- */
- override fun reconcileTiles(tiles: List<TileSpec>): List<TileSpec> {
- val newTiles: MutableList<TileSpec> = mutableListOf()
- val row = TileRow<TileSpec>(columns = gridSizeInteractor.columns.value)
- val tilesQueue: ArrayDeque<SizedTile<TileSpec>> =
- ArrayDeque(
- tiles.map {
- SizedTileImpl(
- it,
- if (iconTilesInteractor.isIconTile(it)) 1 else 2,
- )
- }
- )
-
- while (tilesQueue.isNotEmpty()) {
- if (row.isFull()) {
- newTiles.addAll(row.tiles.map { it.tile })
- row.clear()
- }
-
- val tile = tilesQueue.removeFirst()
-
- // If the tile fits in the row, add it.
- if (!row.maybeAddTile(tile)) {
- // If the tile does not fit the row, find an icon tile to move.
- // We'll try to either add an icon tile from the queue to complete the row, or
- // remove an icon tile from the current row to free up space.
-
- val iconTile: SizedTile<TileSpec>? = tilesQueue.firstOrNull { it.width == 1 }
- if (iconTile != null) {
- tilesQueue.remove(iconTile)
- tilesQueue.addFirst(tile)
- row.maybeAddTile(iconTile)
- } else {
- val tileToRemove: SizedTile<TileSpec>? = row.findLastIconTile()
- if (tileToRemove != null) {
- row.removeTile(tileToRemove)
- row.maybeAddTile(tile)
-
- // Moving the icon tile to the end because there's no other
- // icon tiles in the queue.
- tilesQueue.addLast(tileToRemove)
- } else {
- // If the row does not have an icon tile, add the incomplete row.
- // Note: this shouldn't happen because an icon tile is guaranteed to be in a
- // row that doesn't have enough space for a large tile.
- val tileSpecs = row.tiles.map { it.tile }
- Log.wtf(TAG, "Uneven row does not have an icon tile to remove: $tileSpecs")
- newTiles.addAll(tileSpecs)
- row.clear()
- tilesQueue.addFirst(tile)
- }
- }
- }
- }
-
- // Add last row that might be incomplete
- newTiles.addAll(row.tiles.map { it.tile })
-
- return newTiles.toList()
- }
-
- private companion object {
- const val TAG = "InfiniteGridConsistencyInteractor"
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractor.kt
deleted file mode 100644
index 0386a6a..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractor.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.domain.interactor
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import javax.inject.Inject
-
-/** [GridTypeConsistencyInteractor] implementation that doesn't do any changes to tiles. */
-@SysUISingleton
-class NoopGridConsistencyInteractor @Inject constructor() : GridTypeConsistencyInteractor {
- override fun reconcileTiles(tiles: List<TileSpec>): List<TileSpec> = tiles
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
index 9a2315b..1f8a24a1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt
@@ -161,9 +161,9 @@
@Composable
fun Modifier.dragAndDropTileSource(
sizedTile: SizedTile<EditTileViewModel>,
+ dragAndDropState: DragAndDropState,
onTap: (TileSpec) -> Unit,
- onDoubleTap: (TileSpec) -> Unit,
- dragAndDropState: DragAndDropState
+ onDoubleTap: (TileSpec) -> Unit = {},
): Modifier {
val state by rememberUpdatedState(dragAndDropState)
return dragAndDropSource {
@@ -181,11 +181,11 @@
ClipData(
QsDragAndDrop.CLIPDATA_LABEL,
arrayOf(QsDragAndDrop.TILESPEC_MIME_TYPE),
- ClipData.Item(sizedTile.tile.tileSpec.spec)
+ ClipData.Item(sizedTile.tile.tileSpec.spec),
)
)
)
- }
+ },
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index eeb55ca..f4acbec 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -22,18 +22,18 @@
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.util.fastMap
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.compose.modifiers.sysuiResTag
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.TileLazyGrid
import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel
@Composable
-fun QuickQuickSettings(
- viewModel: QuickQuickSettingsViewModel,
- modifier: Modifier = Modifier,
-) {
+fun QuickQuickSettings(viewModel: QuickQuickSettingsViewModel, modifier: Modifier = Modifier) {
val sizedTiles by
viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList())
- val tiles = sizedTiles.map { it.tile }
+ val tiles = sizedTiles.fastMap { it.tile }
DisposableEffect(tiles) {
val token = Any()
@@ -44,14 +44,18 @@
TileLazyGrid(
modifier = modifier.sysuiResTag("qqs_tile_layout"),
- columns = GridCells.Fixed(columns)
+ columns = GridCells.Fixed(columns),
) {
items(
- tiles.size,
+ sizedTiles.size,
key = { index -> sizedTiles[index].tile.spec.spec },
- span = { index -> GridItemSpan(sizedTiles[index].width) }
+ span = { index -> GridItemSpan(sizedTiles[index].width) },
) { index ->
- Tile(tile = tiles[index], iconOnly = sizedTiles[index].isIcon, modifier = Modifier)
+ Tile(
+ tile = sizedTiles[index].tile,
+ iconOnly = sizedTiles[index].isIcon,
+ modifier = Modifier,
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
deleted file mode 100644
index 93037d1..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
+++ /dev/null
@@ -1,860 +0,0 @@
-/*
- * Copyright (C) 2024 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.
- */
-
-@file:OptIn(ExperimentalFoundationApi::class)
-
-package com.android.systemui.qs.panels.ui.compose
-
-import android.graphics.drawable.Animatable
-import android.service.quicksettings.Tile.STATE_ACTIVE
-import android.service.quicksettings.Tile.STATE_INACTIVE
-import android.text.TextUtils
-import androidx.compose.animation.AnimatedContent
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.core.animateDpAsState
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi
-import androidx.compose.animation.graphics.res.animatedVectorResource
-import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
-import androidx.compose.animation.graphics.vector.AnimatedImageVector
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.LocalOverscrollConfiguration
-import androidx.compose.foundation.background
-import androidx.compose.foundation.basicMarquee
-import androidx.compose.foundation.border
-import androidx.compose.foundation.combinedClickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Arrangement.spacedBy
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.wrapContentSize
-import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.LazyGridItemScope
-import androidx.compose.foundation.lazy.grid.LazyGridScope
-import androidx.compose.foundation.lazy.grid.LazyGridState
-import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
-import androidx.compose.foundation.lazy.grid.rememberLazyGridState
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Clear
-import androidx.compose.material3.Icon
-import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.layout.onGloballyPositioned
-import androidx.compose.ui.layout.positionInRoot
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.res.dimensionResource
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.semantics.onClick
-import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.semantics.stateDescription
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import androidx.compose.ui.util.fastMap
-import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.compose.animation.Expandable
-import com.android.compose.modifiers.background
-import com.android.compose.modifiers.thenIf
-import com.android.systemui.animation.Expandable
-import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.common.ui.compose.Icon
-import com.android.systemui.common.ui.compose.load
-import com.android.systemui.plugins.qs.QSTile
-import com.android.systemui.qs.panels.shared.model.SizedTile
-import com.android.systemui.qs.panels.shared.model.SizedTileImpl
-import com.android.systemui.qs.panels.ui.model.GridCell
-import com.android.systemui.qs.panels.ui.model.SpacerGridCell
-import com.android.systemui.qs.panels.ui.model.TileGridCell
-import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
-import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
-import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
-import com.android.systemui.qs.panels.ui.viewmodel.toUiState
-import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
-import com.android.systemui.qs.pipeline.shared.TileSpec
-import com.android.systemui.qs.shared.model.groupAndSort
-import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.res.R
-import java.util.function.Supplier
-import kotlinx.coroutines.delay
-
-object TileType
-
-@Composable
-fun Tile(
- tile: TileViewModel,
- iconOnly: Boolean,
- showLabels: Boolean = false,
- modifier: Modifier,
-) {
- val state by tile.state.collectAsStateWithLifecycle(tile.currentState)
- val uiState = remember(state) { state.toUiState() }
- val colors = TileDefaults.getColorForState(uiState)
-
- // TODO(b/361789146): Draw the shapes instead of clipping
- val tileShape = TileDefaults.animateTileShape(uiState.state)
-
- TileContainer(
- colors = colors,
- showLabels = showLabels,
- label = uiState.label,
- iconOnly = iconOnly,
- shape = tileShape,
- clickEnabled = true,
- onClick = tile::onClick,
- onLongClick = tile::onLongClick,
- modifier = modifier.height(tileHeight()),
- ) {
- val icon = getTileIcon(icon = uiState.icon)
- if (iconOnly) {
- TileIcon(icon = icon, color = colors.icon, modifier = Modifier.align(Alignment.Center))
- } else {
- val iconShape = TileDefaults.animateIconShape(uiState.state)
- LargeTileContent(
- label = uiState.label,
- secondaryLabel = uiState.secondaryLabel,
- icon = icon,
- colors = colors,
- iconShape = iconShape,
- toggleClickSupported = state.handlesSecondaryClick,
- onClick = {
- if (state.handlesSecondaryClick) {
- tile.onSecondaryClick()
- }
- },
- onLongClick = { tile.onLongClick(it) },
- )
- }
- }
-}
-
-@Composable
-private fun TileContainer(
- colors: TileColors,
- showLabels: Boolean,
- label: String,
- iconOnly: Boolean,
- shape: Shape,
- clickEnabled: Boolean = false,
- onClick: (Expandable) -> Unit = {},
- onLongClick: (Expandable) -> Unit = {},
- modifier: Modifier = Modifier,
- content: @Composable BoxScope.(Expandable) -> Unit,
-) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement =
- spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin), Alignment.Top),
- modifier = modifier,
- ) {
- val backgroundColor =
- if (iconOnly) {
- colors.iconBackground
- } else {
- colors.background
- }
- Expandable(
- color = backgroundColor,
- shape = shape,
- modifier = Modifier.height(tileHeight()).clip(shape)
- ) {
- Box(
- modifier =
- Modifier.fillMaxSize()
- .thenIf(clickEnabled) {
- Modifier.combinedClickable(
- onClick = { onClick(it) },
- onLongClick = { onLongClick(it) }
- )
- }
- .tilePadding(),
- ) {
- content(it)
- }
- }
-
- if (showLabels && iconOnly) {
- Text(
- label,
- maxLines = 2,
- color = colors.label,
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Center,
- )
- }
- }
-}
-
-@Composable
-private fun LargeTileContent(
- label: String,
- secondaryLabel: String?,
- icon: Icon,
- colors: TileColors,
- iconShape: Shape,
- toggleClickSupported: Boolean = false,
- onClick: () -> Unit = {},
- onLongClick: () -> Unit = {},
-) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = tileHorizontalArrangement()
- ) {
- // Icon
- Box(
- modifier =
- Modifier.size(TileDefaults.ToggleTargetSize).thenIf(toggleClickSupported) {
- Modifier.clip(iconShape)
- .background(colors.iconBackground, { 1f })
- .combinedClickable(onClick = onClick, onLongClick = onLongClick)
- }
- ) {
- TileIcon(icon = icon, color = colors.icon, modifier = Modifier.align(Alignment.Center))
- }
-
- // Labels
- Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) {
- Text(
- label,
- color = colors.label,
- modifier = Modifier.tileMarquee(),
- )
- if (!TextUtils.isEmpty(secondaryLabel)) {
- Text(
- secondaryLabel ?: "",
- color = colors.secondaryLabel,
- modifier = Modifier.tileMarquee(),
- )
- }
- }
- }
-}
-
-private fun Modifier.tileMarquee(): Modifier {
- return basicMarquee(
- iterations = 1,
- initialDelayMillis = 200,
- )
-}
-
-@Composable
-fun TileLazyGrid(
- modifier: Modifier = Modifier,
- state: LazyGridState = rememberLazyGridState(),
- columns: GridCells,
- content: LazyGridScope.() -> Unit,
-) {
- LazyVerticalGrid(
- state = state,
- columns = columns,
- verticalArrangement = spacedBy(dimensionResource(R.dimen.qs_tile_margin_vertical)),
- horizontalArrangement = spacedBy(dimensionResource(R.dimen.qs_tile_margin_horizontal)),
- modifier = modifier,
- content = content,
- )
-}
-
-@Composable
-fun DefaultEditTileGrid(
- currentListState: EditTileListState,
- otherTiles: List<SizedTile<EditTileViewModel>>,
- columns: Int,
- modifier: Modifier,
- onAddTile: (TileSpec, Int) -> Unit,
- onRemoveTile: (TileSpec) -> Unit,
- onSetTiles: (List<TileSpec>) -> Unit,
- onResize: (TileSpec) -> Unit,
-) {
- val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
- onAddTile(it, CurrentTilesInteractor.POSITION_AT_END)
- }
- val tilePadding = dimensionResource(R.dimen.qs_tile_margin_vertical)
-
- CompositionLocalProvider(LocalOverscrollConfiguration provides null) {
- Column(
- verticalArrangement =
- spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)),
- modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState())
- ) {
- AnimatedContent(
- targetState = currentListState.dragInProgress,
- modifier = Modifier.wrapContentSize()
- ) { dragIsInProgress ->
- EditGridHeader(Modifier.dragAndDropRemoveZone(currentListState, onRemoveTile)) {
- if (dragIsInProgress) {
- RemoveTileTarget()
- } else {
- Text(text = "Hold and drag to rearrange tiles.")
- }
- }
- }
-
- CurrentTilesGrid(
- currentListState,
- columns,
- tilePadding,
- onRemoveTile,
- onResize,
- onSetTiles,
- )
-
- // Hide available tiles when dragging
- AnimatedVisibility(
- visible = !currentListState.dragInProgress,
- enter = fadeIn(),
- exit = fadeOut()
- ) {
- Column(
- verticalArrangement =
- spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)),
- modifier = modifier.fillMaxSize()
- ) {
- EditGridHeader { Text(text = "Hold and drag to add tiles.") }
-
- AvailableTileGrid(
- otherTiles,
- columns,
- tilePadding,
- addTileToEnd,
- currentListState,
- )
- }
- }
-
- // Drop zone to remove tiles dragged out of the tile grid
- Spacer(
- modifier =
- Modifier.fillMaxWidth()
- .weight(1f)
- .dragAndDropRemoveZone(currentListState, onRemoveTile)
- )
- }
- }
-}
-
-@Composable
-private fun EditGridHeader(
- modifier: Modifier = Modifier,
- content: @Composable BoxScope.() -> Unit
-) {
- CompositionLocalProvider(
- LocalContentColor provides MaterialTheme.colorScheme.onBackground.copy(alpha = .5f)
- ) {
- Box(
- contentAlignment = Alignment.Center,
- modifier = modifier.fillMaxWidth().height(EditModeTileDefaults.EditGridHeaderHeight)
- ) {
- content()
- }
- }
-}
-
-@Composable
-private fun RemoveTileTarget() {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = tileHorizontalArrangement(),
- modifier =
- Modifier.fillMaxHeight()
- .border(1.dp, LocalContentColor.current, shape = CircleShape)
- .padding(10.dp)
- ) {
- Icon(imageVector = Icons.Default.Clear, contentDescription = null)
- Text(text = "Remove")
- }
-}
-
-@Composable
-private fun CurrentTilesContainer(content: @Composable () -> Unit) {
- Box(
- Modifier.fillMaxWidth()
- .border(
- width = 1.dp,
- color = MaterialTheme.colorScheme.onBackground.copy(alpha = .5f),
- shape = RoundedCornerShape(48.dp),
- )
- .padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
- ) {
- content()
- }
-}
-
-@Composable
-private fun CurrentTilesGrid(
- listState: EditTileListState,
- columns: Int,
- tilePadding: Dp,
- onClick: (TileSpec) -> Unit,
- onResize: (TileSpec) -> Unit,
- onSetTiles: (List<TileSpec>) -> Unit,
-) {
- val currentListState by rememberUpdatedState(listState)
-
- CurrentTilesContainer {
- val tileHeight = tileHeight()
- val totalRows = listState.tiles.lastOrNull()?.row ?: 0
- val totalHeight = gridHeight(totalRows + 1, tileHeight, tilePadding)
- val gridState = rememberLazyGridState()
- var gridContentOffset by remember { mutableStateOf(Offset(0f, 0f)) }
-
- TileLazyGrid(
- state = gridState,
- modifier =
- Modifier.height(totalHeight)
- .dragAndDropTileList(gridState, gridContentOffset, listState) {
- onSetTiles(currentListState.tileSpecs())
- }
- .onGloballyPositioned { coordinates ->
- gridContentOffset = coordinates.positionInRoot()
- }
- .testTag(CURRENT_TILES_GRID_TEST_TAG),
- columns = GridCells.Fixed(columns)
- ) {
- editTiles(
- listState.tiles,
- ClickAction.REMOVE,
- onClick,
- listState,
- onResize = onResize,
- indicatePosition = true,
- )
- }
- }
-}
-
-@Composable
-private fun AvailableTileGrid(
- tiles: List<SizedTile<EditTileViewModel>>,
- columns: Int,
- tilePadding: Dp,
- onClick: (TileSpec) -> Unit,
- dragAndDropState: DragAndDropState,
-) {
- val availableTileHeight = tileHeight(true)
- val availableGridHeight = gridHeight(tiles.size, availableTileHeight, columns, tilePadding)
-
- // Available tiles aren't visible during drag and drop, so the row isn't needed
- val groupedTiles =
- remember(tiles.fastMap { it.tile.category }, tiles.fastMap { it.tile.label }) {
- groupAndSort(tiles.fastMap { TileGridCell(it, 0) })
- }
- val labelColors = TileDefaults.inactiveTileColors()
- // Available tiles
- TileLazyGrid(
- modifier = Modifier.height(availableGridHeight).testTag(AVAILABLE_TILES_GRID_TEST_TAG),
- columns = GridCells.Fixed(columns)
- ) {
- groupedTiles.forEach { category, tiles ->
- stickyHeader {
- Text(
- text = category.label.load() ?: "",
- fontSize = 20.sp,
- color = labelColors.label,
- modifier =
- Modifier.background(Color.Black)
- .padding(start = 16.dp, bottom = 8.dp, top = 8.dp)
- )
- }
- editTiles(
- tiles,
- ClickAction.ADD,
- onClick,
- dragAndDropState = dragAndDropState,
- showLabels = true,
- )
- }
- }
-}
-
-fun gridHeight(nTiles: Int, tileHeight: Dp, columns: Int, padding: Dp): Dp {
- val rows = (nTiles + columns - 1) / columns
- return gridHeight(rows, tileHeight, padding)
-}
-
-fun gridHeight(rows: Int, tileHeight: Dp, padding: Dp): Dp {
- return ((tileHeight + padding) * rows) - padding
-}
-
-private fun GridCell.key(index: Int, dragAndDropState: DragAndDropState): Any {
- return if (this is TileGridCell && !dragAndDropState.isMoving(tile.tileSpec)) {
- key
- } else {
- index
- }
-}
-
-fun LazyGridScope.editTiles(
- cells: List<GridCell>,
- clickAction: ClickAction,
- onClick: (TileSpec) -> Unit,
- dragAndDropState: DragAndDropState,
- onResize: (TileSpec) -> Unit = {},
- showLabels: Boolean = false,
- indicatePosition: Boolean = false,
-) {
- items(
- count = cells.size,
- key = { cells[it].key(it, dragAndDropState) },
- span = { cells[it].span },
- contentType = { TileType }
- ) { index ->
- when (val cell = cells[index]) {
- is TileGridCell ->
- if (dragAndDropState.isMoving(cell.tile.tileSpec)) {
- // If the tile is being moved, replace it with a visible spacer
- SpacerGridCell(
- Modifier.background(
- color = MaterialTheme.colorScheme.secondary,
- alpha = { EditModeTileDefaults.PLACEHOLDER_ALPHA },
- shape = RoundedCornerShape(TileDefaults.InactiveCornerRadius)
- )
- .animateItem()
- )
- } else {
- TileGridCell(
- cell = cell,
- index = index,
- dragAndDropState = dragAndDropState,
- clickAction = clickAction,
- onClick = onClick,
- onResize = onResize,
- showLabels = showLabels,
- indicatePosition = indicatePosition
- )
- }
- is SpacerGridCell -> SpacerGridCell()
- }
- }
-}
-
-@Composable
-private fun LazyGridItemScope.TileGridCell(
- cell: TileGridCell,
- index: Int,
- dragAndDropState: DragAndDropState,
- clickAction: ClickAction,
- onClick: (TileSpec) -> Unit,
- onResize: (TileSpec) -> Unit = {},
- showLabels: Boolean = false,
- indicatePosition: Boolean = false,
-) {
- val tileHeight = tileHeight(cell.isIcon && showLabels)
- val onClickActionName =
- when (clickAction) {
- ClickAction.ADD -> stringResource(id = R.string.accessibility_qs_edit_tile_add_action)
- ClickAction.REMOVE ->
- stringResource(id = R.string.accessibility_qs_edit_remove_tile_action)
- }
- val stateDescription =
- if (indicatePosition) {
- stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
- } else {
- ""
- }
- EditTile(
- tileViewModel = cell.tile,
- iconOnly = cell.isIcon,
- showLabels = showLabels,
- modifier =
- Modifier.height(tileHeight)
- .animateItem()
- .semantics {
- onClick(onClickActionName) { false }
- this.stateDescription = stateDescription
- }
- .dragAndDropTileSource(
- SizedTileImpl(cell.tile, cell.width),
- onClick,
- onResize,
- dragAndDropState,
- )
- )
-}
-
-@Composable
-private fun SpacerGridCell(modifier: Modifier = Modifier) {
- // By default, spacers are invisible and exist purely to catch drag movements
- Box(modifier.height(tileHeight()).fillMaxWidth().tilePadding())
-}
-
-@Composable
-fun EditTile(
- tileViewModel: EditTileViewModel,
- iconOnly: Boolean,
- showLabels: Boolean,
- modifier: Modifier = Modifier,
-) {
- val label = tileViewModel.label.text
- val colors = TileDefaults.inactiveTileColors()
-
- TileContainer(
- colors = colors,
- showLabels = showLabels,
- label = label,
- iconOnly = iconOnly,
- shape = RoundedCornerShape(TileDefaults.InactiveCornerRadius),
- modifier = modifier,
- ) {
- if (iconOnly) {
- TileIcon(
- icon = tileViewModel.icon,
- color = colors.icon,
- modifier = Modifier.align(Alignment.Center)
- )
- } else {
- LargeTileContent(
- label = label,
- secondaryLabel = tileViewModel.appName?.text,
- icon = tileViewModel.icon,
- colors = colors,
- iconShape = RoundedCornerShape(TileDefaults.InactiveCornerRadius),
- )
- }
- }
-}
-
-enum class ClickAction {
- ADD,
- REMOVE,
-}
-
-@Composable
-private fun getTileIcon(icon: Supplier<QSTile.Icon?>): Icon {
- val context = LocalContext.current
- return icon.get()?.let {
- if (it is QSTileImpl.ResourceIcon) {
- Icon.Resource(it.resId, null)
- } else {
- Icon.Loaded(it.getDrawable(context), null)
- }
- } ?: Icon.Resource(R.drawable.ic_error_outline, null)
-}
-
-@OptIn(ExperimentalAnimationGraphicsApi::class)
-@Composable
-private fun TileIcon(
- icon: Icon,
- color: Color,
- animateToEnd: Boolean = false,
- modifier: Modifier = Modifier,
-) {
- val iconModifier = modifier.size(TileDefaults.IconSize)
- val context = LocalContext.current
- val loadedDrawable =
- remember(icon, context) {
- when (icon) {
- is Icon.Loaded -> icon.drawable
- is Icon.Resource -> context.getDrawable(icon.res)
- }
- }
- if (loadedDrawable !is Animatable) {
- Icon(
- icon = icon,
- tint = color,
- modifier = iconModifier,
- )
- } else if (icon is Icon.Resource) {
- val image = AnimatedImageVector.animatedVectorResource(id = icon.res)
- val painter =
- if (animateToEnd) {
- rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true)
- } else {
- var atEnd by remember(icon.res) { mutableStateOf(false) }
- LaunchedEffect(key1 = icon.res) {
- delay(350)
- atEnd = true
- }
- rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd)
- }
- Image(
- painter = painter,
- contentDescription = icon.contentDescription?.load(),
- colorFilter = ColorFilter.tint(color = color),
- modifier = iconModifier
- )
- }
-}
-
-private fun Modifier.tilePadding(): Modifier {
- return padding(TileDefaults.TilePadding)
-}
-
-private fun tileHorizontalArrangement(): Arrangement.Horizontal {
- return spacedBy(space = TileDefaults.TileArrangementPadding, alignment = Alignment.Start)
-}
-
-@Composable
-fun tileHeight(iconWithLabel: Boolean = false): Dp {
- return if (iconWithLabel) {
- TileDefaults.IconTileWithLabelHeight
- } else {
- TileDefaults.TileHeight
- }
-}
-
-private data class TileColors(
- val background: Color,
- val iconBackground: Color,
- val label: Color,
- val secondaryLabel: Color,
- val icon: Color,
-)
-
-private object EditModeTileDefaults {
- const val PLACEHOLDER_ALPHA = .3f
- val EditGridHeaderHeight = 60.dp
-}
-
-private object TileDefaults {
- val InactiveCornerRadius = 50.dp
- val ActiveIconCornerRadius = 16.dp
- val ActiveTileCornerRadius = 24.dp
-
- val ToggleTargetSize = 56.dp
- val IconSize = 24.dp
-
- val TilePadding = 8.dp
- val TileArrangementPadding = 6.dp
-
- val TileHeight = 72.dp
- val IconTileWithLabelHeight = 140.dp
-
- /** An active tile without dual target uses the active color as background */
- @Composable
- fun activeTileColors(): TileColors =
- TileColors(
- background = MaterialTheme.colorScheme.primary,
- iconBackground = MaterialTheme.colorScheme.primary,
- label = MaterialTheme.colorScheme.onPrimary,
- secondaryLabel = MaterialTheme.colorScheme.onPrimary,
- icon = MaterialTheme.colorScheme.onPrimary,
- )
-
- /** An active tile with dual target only show the active color on the icon */
- @Composable
- fun activeDualTargetTileColors(): TileColors =
- TileColors(
- background = MaterialTheme.colorScheme.surfaceVariant,
- iconBackground = MaterialTheme.colorScheme.primary,
- label = MaterialTheme.colorScheme.onSurfaceVariant,
- secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
- icon = MaterialTheme.colorScheme.onPrimary,
- )
-
- @Composable
- fun inactiveTileColors(): TileColors =
- TileColors(
- background = MaterialTheme.colorScheme.surfaceVariant,
- iconBackground = MaterialTheme.colorScheme.surfaceVariant,
- label = MaterialTheme.colorScheme.onSurfaceVariant,
- secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
- icon = MaterialTheme.colorScheme.onSurfaceVariant,
- )
-
- @Composable
- fun unavailableTileColors(): TileColors =
- TileColors(
- background = MaterialTheme.colorScheme.surface,
- iconBackground = MaterialTheme.colorScheme.surface,
- label = MaterialTheme.colorScheme.onSurface,
- secondaryLabel = MaterialTheme.colorScheme.onSurface,
- icon = MaterialTheme.colorScheme.onSurface,
- )
-
- @Composable
- fun getColorForState(uiState: TileUiState): TileColors {
- return when (uiState.state) {
- STATE_ACTIVE -> {
- if (uiState.handlesSecondaryClick) {
- activeDualTargetTileColors()
- } else {
- activeTileColors()
- }
- }
- STATE_INACTIVE -> inactiveTileColors()
- else -> unavailableTileColors()
- }
- }
-
- @Composable
- fun animateIconShape(state: Int): Shape {
- return animateShape(
- state = state,
- activeCornerRadius = ActiveIconCornerRadius,
- label = "QSTileCornerRadius",
- )
- }
-
- @Composable
- fun animateTileShape(state: Int): Shape {
- return animateShape(
- state = state,
- activeCornerRadius = ActiveTileCornerRadius,
- label = "QSTileIconCornerRadius",
- )
- }
-
- @Composable
- fun animateShape(state: Int, activeCornerRadius: Dp, label: String): Shape {
- val animatedCornerRadius by
- animateDpAsState(
- targetValue =
- if (state == STATE_ACTIVE) {
- activeCornerRadius
- } else {
- InactiveCornerRadius
- },
- label = label
- )
- return RoundedCornerShape(animatedCornerRadius)
- }
-}
-
-private const val CURRENT_TILES_GRID_TEST_TAG = "CurrentTilesGrid"
-private const val AVAILABLE_TILES_GRID_TEST_TAG = "AvailableTilesGrid"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
new file mode 100644
index 0000000..aeb6031
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.compose.infinitegrid
+
+import android.graphics.drawable.Animatable
+import android.text.TextUtils
+import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi
+import androidx.compose.animation.graphics.res.animatedVectorResource
+import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
+import androidx.compose.animation.graphics.vector.AnimatedImageVector
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.clearAndSetSemantics
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.stateDescription
+import androidx.compose.ui.semantics.toggleableState
+import androidx.compose.ui.unit.dp
+import com.android.compose.modifiers.background
+import com.android.compose.modifiers.thenIf
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.common.ui.compose.load
+import com.android.systemui.compose.modifiers.sysuiResTag
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
+import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState
+import com.android.systemui.res.R
+import kotlinx.coroutines.delay
+
+private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target"
+
+@Composable
+fun LargeTileContent(
+ label: String,
+ secondaryLabel: String?,
+ icon: Icon,
+ colors: TileColors,
+ accessibilityUiState: AccessibilityUiState? = null,
+ toggleClickSupported: Boolean = false,
+ iconShape: Shape = RoundedCornerShape(CommonTileDefaults.InactiveCornerRadius),
+ onClick: () -> Unit = {},
+ onLongClick: () -> Unit = {},
+) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = tileHorizontalArrangement(),
+ ) {
+ // Icon
+ val longPressLabel = longPressLabel()
+ Box(
+ modifier =
+ Modifier.size(CommonTileDefaults.ToggleTargetSize).thenIf(toggleClickSupported) {
+ Modifier.clip(iconShape)
+ .background(colors.iconBackground, { 1f })
+ .combinedClickable(
+ onClick = onClick,
+ onLongClick = onLongClick,
+ onLongClickLabel = longPressLabel,
+ )
+ .thenIf(accessibilityUiState != null) {
+ Modifier.semantics {
+ accessibilityUiState as AccessibilityUiState
+ contentDescription = accessibilityUiState.contentDescription
+ stateDescription = accessibilityUiState.stateDescription
+ accessibilityUiState.toggleableState?.let {
+ toggleableState = it
+ }
+ role = Role.Switch
+ }
+ .sysuiResTag(TEST_TAG_TOGGLE)
+ }
+ }
+ ) {
+ SmallTileContent(
+ icon = icon,
+ color = colors.icon,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ }
+
+ // Labels
+ LargeTileLabels(
+ label = label,
+ secondaryLabel = secondaryLabel,
+ colors = colors,
+ accessibilityUiState = accessibilityUiState,
+ )
+ }
+}
+
+@Composable
+private fun LargeTileLabels(
+ label: String,
+ secondaryLabel: String?,
+ colors: TileColors,
+ accessibilityUiState: AccessibilityUiState? = null,
+) {
+ Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) {
+ Text(label, color = colors.label, modifier = Modifier.tileMarquee())
+ if (!TextUtils.isEmpty(secondaryLabel)) {
+ Text(
+ secondaryLabel ?: "",
+ color = colors.secondaryLabel,
+ modifier =
+ Modifier.tileMarquee().thenIf(
+ accessibilityUiState?.stateDescription?.contains(secondaryLabel ?: "") ==
+ true
+ ) {
+ Modifier.clearAndSetSemantics {}
+ },
+ )
+ }
+ }
+}
+
+@OptIn(ExperimentalAnimationGraphicsApi::class)
+@Composable
+fun SmallTileContent(
+ modifier: Modifier = Modifier,
+ icon: Icon,
+ color: Color,
+ animateToEnd: Boolean = false,
+) {
+ val iconModifier = modifier.size(CommonTileDefaults.IconSize)
+ val context = LocalContext.current
+ val loadedDrawable =
+ remember(icon, context) {
+ when (icon) {
+ is Icon.Loaded -> icon.drawable
+ is Icon.Resource -> context.getDrawable(icon.res)
+ }
+ }
+ if (loadedDrawable !is Animatable) {
+ Icon(icon = icon, tint = color, modifier = iconModifier)
+ } else if (icon is Icon.Resource) {
+ val image = AnimatedImageVector.animatedVectorResource(id = icon.res)
+ val painter =
+ if (animateToEnd) {
+ rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true)
+ } else {
+ var atEnd by remember(icon.res) { mutableStateOf(false) }
+ LaunchedEffect(key1 = icon.res) {
+ delay(350)
+ atEnd = true
+ }
+ rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd)
+ }
+ Image(
+ painter = painter,
+ contentDescription = icon.contentDescription?.load(),
+ colorFilter = ColorFilter.tint(color = color),
+ modifier = iconModifier,
+ )
+ }
+}
+
+object CommonTileDefaults {
+ val IconSize = 24.dp
+ val ToggleTargetSize = 56.dp
+ val TileHeight = 72.dp
+ val TilePadding = 8.dp
+ val TileArrangementPadding = 6.dp
+ val InactiveCornerRadius = 50.dp
+
+ @Composable fun longPressLabel() = stringResource(id = R.string.accessibility_long_click_tile)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
new file mode 100644
index 0000000..a43b880
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package com.android.systemui.qs.panels.ui.compose.infinitegrid
+
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.LocalOverscrollConfiguration
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement.spacedBy
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyGridItemScope
+import androidx.compose.foundation.lazy.grid.LazyGridScope
+import androidx.compose.foundation.lazy.grid.rememberLazyGridState
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Clear
+import androidx.compose.material3.Icon
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.layout.positionInRoot
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.semantics.onClick
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.stateDescription
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.compose.ui.util.fastMap
+import com.android.compose.modifiers.background
+import com.android.systemui.common.ui.compose.load
+import com.android.systemui.qs.panels.shared.model.SizedTile
+import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.compose.DragAndDropState
+import com.android.systemui.qs.panels.ui.compose.EditTileListState
+import com.android.systemui.qs.panels.ui.compose.dragAndDropRemoveZone
+import com.android.systemui.qs.panels.ui.compose.dragAndDropTileList
+import com.android.systemui.qs.panels.ui.compose.dragAndDropTileSource
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
+import com.android.systemui.qs.panels.ui.model.GridCell
+import com.android.systemui.qs.panels.ui.model.SpacerGridCell
+import com.android.systemui.qs.panels.ui.model.TileGridCell
+import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
+import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.shared.model.groupAndSort
+import com.android.systemui.res.R
+
+object TileType
+
+@Composable
+fun DefaultEditTileGrid(
+ currentListState: EditTileListState,
+ otherTiles: List<SizedTile<EditTileViewModel>>,
+ columns: Int,
+ modifier: Modifier,
+ onAddTile: (TileSpec, Int) -> Unit,
+ onRemoveTile: (TileSpec) -> Unit,
+ onSetTiles: (List<TileSpec>) -> Unit,
+ onResize: (TileSpec) -> Unit,
+) {
+ val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
+ onAddTile(it, CurrentTilesInteractor.POSITION_AT_END)
+ }
+
+ CompositionLocalProvider(LocalOverscrollConfiguration provides null) {
+ Column(
+ verticalArrangement =
+ spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)),
+ modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState()),
+ ) {
+ AnimatedContent(
+ targetState = currentListState.dragInProgress,
+ modifier = Modifier.wrapContentSize(),
+ label = "",
+ ) { dragIsInProgress ->
+ EditGridHeader(Modifier.dragAndDropRemoveZone(currentListState, onRemoveTile)) {
+ if (dragIsInProgress) {
+ RemoveTileTarget()
+ } else {
+ Text(text = "Hold and drag to rearrange tiles.")
+ }
+ }
+ }
+
+ CurrentTilesGrid(currentListState, columns, onRemoveTile, onResize, onSetTiles)
+
+ // Hide available tiles when dragging
+ AnimatedVisibility(
+ visible = !currentListState.dragInProgress,
+ enter = fadeIn(),
+ exit = fadeOut(),
+ ) {
+ Column(
+ verticalArrangement =
+ spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)),
+ modifier = modifier.fillMaxSize(),
+ ) {
+ EditGridHeader { Text(text = "Hold and drag to add tiles.") }
+
+ AvailableTileGrid(otherTiles, columns, addTileToEnd, currentListState)
+ }
+ }
+
+ // Drop zone to remove tiles dragged out of the tile grid
+ Spacer(
+ modifier =
+ Modifier.fillMaxWidth()
+ .weight(1f)
+ .dragAndDropRemoveZone(currentListState, onRemoveTile)
+ )
+ }
+ }
+}
+
+@Composable
+private fun EditGridHeader(
+ modifier: Modifier = Modifier,
+ content: @Composable BoxScope.() -> Unit,
+) {
+ CompositionLocalProvider(
+ LocalContentColor provides MaterialTheme.colorScheme.onBackground.copy(alpha = .5f)
+ ) {
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = modifier.fillMaxWidth().height(EditModeTileDefaults.EditGridHeaderHeight),
+ ) {
+ content()
+ }
+ }
+}
+
+@Composable
+private fun RemoveTileTarget() {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = tileHorizontalArrangement(),
+ modifier =
+ Modifier.fillMaxHeight()
+ .border(1.dp, LocalContentColor.current, shape = CircleShape)
+ .padding(10.dp),
+ ) {
+ Icon(imageVector = Icons.Default.Clear, contentDescription = null)
+ Text(text = "Remove")
+ }
+}
+
+@Composable
+private fun CurrentTilesContainer(content: @Composable () -> Unit) {
+ Box(
+ Modifier.fillMaxWidth()
+ .border(
+ width = 1.dp,
+ color = MaterialTheme.colorScheme.onBackground.copy(alpha = .5f),
+ shape = RoundedCornerShape(48.dp),
+ )
+ .padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
+ ) {
+ content()
+ }
+}
+
+@Composable
+private fun CurrentTilesGrid(
+ listState: EditTileListState,
+ columns: Int,
+ onClick: (TileSpec) -> Unit,
+ onResize: (TileSpec) -> Unit,
+ onSetTiles: (List<TileSpec>) -> Unit,
+) {
+ val currentListState by rememberUpdatedState(listState)
+ val tilePadding = CommonTileDefaults.TileArrangementPadding
+
+ CurrentTilesContainer {
+ val tileHeight = CommonTileDefaults.TileHeight
+ val totalRows = listState.tiles.lastOrNull()?.row ?: 0
+ val totalHeight = gridHeight(totalRows + 1, tileHeight, tilePadding)
+ val gridState = rememberLazyGridState()
+ var gridContentOffset by remember { mutableStateOf(Offset(0f, 0f)) }
+
+ TileLazyGrid(
+ state = gridState,
+ modifier =
+ Modifier.height(totalHeight)
+ .dragAndDropTileList(gridState, gridContentOffset, listState) {
+ onSetTiles(currentListState.tileSpecs())
+ }
+ .onGloballyPositioned { coordinates ->
+ gridContentOffset = coordinates.positionInRoot()
+ }
+ .testTag(CURRENT_TILES_GRID_TEST_TAG),
+ columns = GridCells.Fixed(columns),
+ ) {
+ EditTiles(listState.tiles, onClick, listState, onResize = onResize)
+ }
+ }
+}
+
+@Composable
+private fun AvailableTileGrid(
+ tiles: List<SizedTile<EditTileViewModel>>,
+ columns: Int,
+ onClick: (TileSpec) -> Unit,
+ dragAndDropState: DragAndDropState,
+) {
+ // Available tiles aren't visible during drag and drop, so the row isn't needed
+ val groupedTiles =
+ remember(tiles.fastMap { it.tile.category }, tiles.fastMap { it.tile.label }) {
+ groupAndSort(tiles.fastMap { TileGridCell(it, 0) })
+ }
+ val labelColors = EditModeTileDefaults.editTileColors()
+
+ // Available tiles
+ Column(
+ verticalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+ horizontalAlignment = Alignment.Start,
+ modifier =
+ Modifier.fillMaxWidth().wrapContentHeight().testTag(AVAILABLE_TILES_GRID_TEST_TAG),
+ ) {
+ groupedTiles.forEach { (category, tiles) ->
+ Text(
+ text = category.label.load() ?: "",
+ fontSize = 20.sp,
+ color = labelColors.label,
+ modifier =
+ Modifier.fillMaxWidth()
+ .background(Color.Black)
+ .padding(start = 16.dp, bottom = 8.dp, top = 8.dp),
+ )
+ tiles.chunked(columns).forEach { row ->
+ Row(
+ horizontalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+ modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max),
+ ) {
+ row.forEachIndexed { index, tileGridCell ->
+ AvailableTileGridCell(
+ cell = tileGridCell,
+ index = index,
+ dragAndDropState = dragAndDropState,
+ onClick = onClick,
+ modifier = Modifier.weight(1f).fillMaxHeight(),
+ )
+ }
+
+ // Spacers for incomplete rows
+ repeat(columns - row.size) { Spacer(modifier = Modifier.weight(1f)) }
+ }
+ }
+ }
+ }
+}
+
+fun gridHeight(rows: Int, tileHeight: Dp, padding: Dp): Dp {
+ return ((tileHeight + padding) * rows) - padding
+}
+
+private fun GridCell.key(index: Int, dragAndDropState: DragAndDropState): Any {
+ return when (this) {
+ is TileGridCell -> {
+ if (dragAndDropState.isMoving(tile.tileSpec)) index else key
+ }
+ is SpacerGridCell -> index
+ }
+}
+
+fun LazyGridScope.EditTiles(
+ cells: List<GridCell>,
+ onClick: (TileSpec) -> Unit,
+ dragAndDropState: DragAndDropState,
+ onResize: (TileSpec) -> Unit = {},
+) {
+ items(
+ count = cells.size,
+ key = { cells[it].key(it, dragAndDropState) },
+ span = { cells[it].span },
+ contentType = { TileType },
+ ) { index ->
+ when (val cell = cells[index]) {
+ is TileGridCell ->
+ if (dragAndDropState.isMoving(cell.tile.tileSpec)) {
+ // If the tile is being moved, replace it with a visible spacer
+ SpacerGridCell(
+ Modifier.background(
+ color = MaterialTheme.colorScheme.secondary,
+ alpha = { EditModeTileDefaults.PLACEHOLDER_ALPHA },
+ shape = RoundedCornerShape(InactiveCornerRadius),
+ )
+ .animateItem()
+ )
+ } else {
+ TileGridCell(
+ cell = cell,
+ index = index,
+ dragAndDropState = dragAndDropState,
+ onClick = onClick,
+ onResize = onResize,
+ )
+ }
+ is SpacerGridCell -> SpacerGridCell()
+ }
+ }
+}
+
+@Composable
+private fun LazyGridItemScope.TileGridCell(
+ cell: TileGridCell,
+ index: Int,
+ dragAndDropState: DragAndDropState,
+ onClick: (TileSpec) -> Unit,
+ onResize: (TileSpec) -> Unit = {},
+) {
+ val onClickActionName = stringResource(id = R.string.accessibility_qs_edit_remove_tile_action)
+ val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
+
+ EditTile(
+ tileViewModel = cell.tile,
+ iconOnly = cell.isIcon,
+ modifier =
+ Modifier.animateItem()
+ .semantics(mergeDescendants = true) {
+ onClick(onClickActionName) { false }
+ this.stateDescription = stateDescription
+ }
+ .dragAndDropTileSource(
+ SizedTileImpl(cell.tile, cell.width),
+ dragAndDropState,
+ onClick,
+ onResize,
+ ),
+ )
+}
+
+@Composable
+private fun AvailableTileGridCell(
+ cell: TileGridCell,
+ index: Int,
+ dragAndDropState: DragAndDropState,
+ modifier: Modifier = Modifier,
+ onClick: (TileSpec) -> Unit,
+) {
+ val onClickActionName = stringResource(id = R.string.accessibility_qs_edit_tile_add_action)
+ val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
+ val colors = EditModeTileDefaults.editTileColors()
+
+ // Displays the tile as an icon tile with the label underneath
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top),
+ modifier = modifier,
+ ) {
+ EditTile(
+ tileViewModel = cell.tile,
+ iconOnly = true,
+ colors = colors,
+ modifier =
+ Modifier.semantics(mergeDescendants = true) {
+ onClick(onClickActionName) { false }
+ this.stateDescription = stateDescription
+ }
+ .dragAndDropTileSource(
+ SizedTileImpl(cell.tile, cell.width),
+ dragAndDropState,
+ onTap = onClick,
+ ),
+ )
+ Box(Modifier.fillMaxSize()) {
+ Text(
+ cell.tile.label.text,
+ maxLines = 2,
+ color = colors.label,
+ overflow = TextOverflow.Ellipsis,
+ textAlign = TextAlign.Center,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ }
+ }
+}
+
+@Composable
+private fun SpacerGridCell(modifier: Modifier = Modifier) {
+ // By default, spacers are invisible and exist purely to catch drag movements
+ Box(modifier.height(CommonTileDefaults.TileHeight).fillMaxWidth().tilePadding())
+}
+
+@Composable
+fun EditTile(
+ tileViewModel: EditTileViewModel,
+ iconOnly: Boolean,
+ modifier: Modifier = Modifier,
+ colors: TileColors = EditModeTileDefaults.editTileColors(),
+) {
+ EditTileContainer(colors = colors, modifier = modifier) {
+ if (iconOnly) {
+ SmallTileContent(
+ icon = tileViewModel.icon,
+ color = colors.icon,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ } else {
+ LargeTileContent(
+ label = tileViewModel.label.text,
+ secondaryLabel = tileViewModel.appName?.text,
+ icon = tileViewModel.icon,
+ colors = colors,
+ )
+ }
+ }
+}
+
+@Composable
+private fun EditTileContainer(
+ colors: TileColors,
+ modifier: Modifier = Modifier,
+ content: @Composable BoxScope.() -> Unit,
+) {
+ Box(
+ modifier =
+ modifier
+ .height(CommonTileDefaults.TileHeight)
+ .fillMaxWidth()
+ .drawBehind {
+ drawRoundRect(
+ SolidColor(colors.background),
+ cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
+ )
+ }
+ .tilePadding(),
+ content = content,
+ )
+}
+
+private object EditModeTileDefaults {
+ const val PLACEHOLDER_ALPHA = .3f
+ val EditGridHeaderHeight = 60.dp
+
+ @Composable
+ fun editTileColors(): TileColors =
+ TileColors(
+ background = MaterialTheme.colorScheme.surfaceVariant,
+ iconBackground = MaterialTheme.colorScheme.surfaceVariant,
+ label = MaterialTheme.colorScheme.onSurfaceVariant,
+ secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
+ icon = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+}
+
+private const val CURRENT_TILES_GRID_TEST_TAG = "CurrentTilesGrid"
+private const val AVAILABLE_TILES_GRID_TEST_TAG = "AvailableTilesGrid"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
rename to packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index c75b601..f96c27d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs.panels.ui.compose
+package com.android.systemui.qs.panels.ui.compose.infinitegrid
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
@@ -26,6 +26,8 @@
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
+import com.android.systemui.qs.panels.ui.compose.rememberEditListState
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.panels.ui.viewmodel.FixedColumnsSizeViewModel
import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel
@@ -61,7 +63,7 @@
Tile(
tile = sizedTiles[index].tile,
iconOnly = iconTilesViewModel.isIconTile(sizedTiles[index].tile.spec),
- modifier = Modifier
+ modifier = Modifier,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
new file mode 100644
index 0000000..aa6c08e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package com.android.systemui.qs.panels.ui.compose.infinitegrid
+
+import android.content.res.Resources
+import android.service.quicksettings.Tile.STATE_ACTIVE
+import android.service.quicksettings.Tile.STATE_INACTIVE
+import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.basicMarquee
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Arrangement.spacedBy
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyGridScope
+import androidx.compose.foundation.lazy.grid.LazyGridState
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.rememberLazyGridState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.stateDescription
+import androidx.compose.ui.semantics.toggleableState
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.animation.Expandable
+import com.android.compose.modifiers.thenIf
+import com.android.systemui.animation.Expandable
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.compose.modifiers.sysuiResTag
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
+import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
+import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.toUiState
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.res.R
+import java.util.function.Supplier
+
+private const val TEST_TAG_SMALL = "qs_tile_small"
+private const val TEST_TAG_LARGE = "qs_tile_large"
+
+@Composable
+fun TileLazyGrid(
+ columns: GridCells,
+ modifier: Modifier = Modifier,
+ state: LazyGridState = rememberLazyGridState(),
+ content: LazyGridScope.() -> Unit,
+) {
+ LazyVerticalGrid(
+ state = state,
+ columns = columns,
+ verticalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+ horizontalArrangement = spacedBy(CommonTileDefaults.TileArrangementPadding),
+ modifier = modifier,
+ content = content,
+ )
+}
+
+@Composable
+fun Tile(tile: TileViewModel, iconOnly: Boolean, modifier: Modifier) {
+ val state by tile.state.collectAsStateWithLifecycle(tile.currentState)
+ val resources = resources()
+ val uiState = remember(state, resources) { state.toUiState(resources) }
+ val colors = TileDefaults.getColorForState(uiState)
+
+ // TODO(b/361789146): Draw the shapes instead of clipping
+ val tileShape = TileDefaults.animateTileShape(uiState.state)
+
+ TileContainer(
+ color =
+ if (iconOnly || !uiState.handlesSecondaryClick) {
+ colors.iconBackground
+ } else {
+ colors.background
+ },
+ shape = tileShape,
+ iconOnly = iconOnly,
+ onClick = tile::onClick,
+ onLongClick = tile::onLongClick,
+ uiState = uiState,
+ modifier = modifier,
+ ) { expandable ->
+ val icon = getTileIcon(icon = uiState.icon)
+ if (iconOnly) {
+ SmallTileContent(
+ icon = icon,
+ color = colors.icon,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ } else {
+ val iconShape = TileDefaults.animateIconShape(uiState.state)
+ LargeTileContent(
+ label = uiState.label,
+ secondaryLabel = uiState.secondaryLabel,
+ icon = icon,
+ colors = colors,
+ iconShape = iconShape,
+ toggleClickSupported = state.handlesSecondaryClick,
+ onClick = {
+ if (state.handlesSecondaryClick) {
+ tile.onSecondaryClick()
+ }
+ },
+ onLongClick = { tile.onLongClick(expandable) },
+ )
+ }
+ }
+}
+
+@Composable
+private fun TileContainer(
+ color: Color,
+ shape: Shape,
+ iconOnly: Boolean,
+ uiState: TileUiState,
+ modifier: Modifier = Modifier,
+ onClick: (Expandable) -> Unit = {},
+ onLongClick: (Expandable) -> Unit = {},
+ content: @Composable BoxScope.(Expandable) -> Unit,
+) {
+ Expandable(color = color, shape = shape, modifier = modifier.clip(shape)) {
+ val longPressLabel = longPressLabel()
+ Box(
+ modifier =
+ Modifier.height(CommonTileDefaults.TileHeight)
+ .fillMaxWidth()
+ .combinedClickable(
+ onClick = { onClick(it) },
+ onLongClick = { onLongClick(it) },
+ onClickLabel = uiState.accessibilityUiState.clickLabel,
+ onLongClickLabel = longPressLabel,
+ )
+ .semantics {
+ role = uiState.accessibilityUiState.accessibilityRole
+ if (uiState.accessibilityUiState.accessibilityRole == Role.Switch) {
+ uiState.accessibilityUiState.toggleableState?.let {
+ toggleableState = it
+ }
+ }
+ stateDescription = uiState.accessibilityUiState.stateDescription
+ }
+ .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE)
+ .thenIf(iconOnly) {
+ Modifier.semantics {
+ contentDescription = uiState.accessibilityUiState.contentDescription
+ }
+ }
+ .tilePadding()
+ ) {
+ content(it)
+ }
+ }
+}
+
+@Composable
+private fun getTileIcon(icon: Supplier<QSTile.Icon?>): Icon {
+ val context = LocalContext.current
+ return icon.get()?.let {
+ if (it is QSTileImpl.ResourceIcon) {
+ Icon.Resource(it.resId, null)
+ } else {
+ Icon.Loaded(it.getDrawable(context), null)
+ }
+ } ?: Icon.Resource(R.drawable.ic_error_outline, null)
+}
+
+fun tileHorizontalArrangement(): Arrangement.Horizontal {
+ return spacedBy(space = CommonTileDefaults.TileArrangementPadding, alignment = Alignment.Start)
+}
+
+fun Modifier.tileMarquee(): Modifier {
+ return basicMarquee(iterations = 1, initialDelayMillis = 200)
+}
+
+fun Modifier.tilePadding(): Modifier {
+ return padding(CommonTileDefaults.TilePadding)
+}
+
+data class TileColors(
+ val background: Color,
+ val iconBackground: Color,
+ val label: Color,
+ val secondaryLabel: Color,
+ val icon: Color,
+)
+
+private object TileDefaults {
+ val ActiveIconCornerRadius = 16.dp
+ val ActiveTileCornerRadius = 24.dp
+
+ /** An active tile without dual target uses the active color as background */
+ @Composable
+ fun activeTileColors(): TileColors =
+ TileColors(
+ background = MaterialTheme.colorScheme.primary,
+ iconBackground = MaterialTheme.colorScheme.primary,
+ label = MaterialTheme.colorScheme.onPrimary,
+ secondaryLabel = MaterialTheme.colorScheme.onPrimary,
+ icon = MaterialTheme.colorScheme.onPrimary,
+ )
+
+ /** An active tile with dual target only show the active color on the icon */
+ @Composable
+ fun activeDualTargetTileColors(): TileColors =
+ TileColors(
+ background = MaterialTheme.colorScheme.surfaceVariant,
+ iconBackground = MaterialTheme.colorScheme.primary,
+ label = MaterialTheme.colorScheme.onSurfaceVariant,
+ secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
+ icon = MaterialTheme.colorScheme.onPrimary,
+ )
+
+ @Composable
+ fun inactiveTileColors(): TileColors =
+ TileColors(
+ background = MaterialTheme.colorScheme.surfaceVariant,
+ iconBackground = MaterialTheme.colorScheme.surfaceVariant,
+ label = MaterialTheme.colorScheme.onSurfaceVariant,
+ secondaryLabel = MaterialTheme.colorScheme.onSurfaceVariant,
+ icon = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+
+ @Composable
+ fun unavailableTileColors(): TileColors =
+ TileColors(
+ background = MaterialTheme.colorScheme.surface,
+ iconBackground = MaterialTheme.colorScheme.surface,
+ label = MaterialTheme.colorScheme.onSurface,
+ secondaryLabel = MaterialTheme.colorScheme.onSurface,
+ icon = MaterialTheme.colorScheme.onSurface,
+ )
+
+ @Composable
+ fun getColorForState(uiState: TileUiState): TileColors {
+ return when (uiState.state) {
+ STATE_ACTIVE -> {
+ if (uiState.handlesSecondaryClick) {
+ activeDualTargetTileColors()
+ } else {
+ activeTileColors()
+ }
+ }
+ STATE_INACTIVE -> inactiveTileColors()
+ else -> unavailableTileColors()
+ }
+ }
+
+ @Composable
+ fun animateIconShape(state: Int): Shape {
+ return animateShape(
+ state = state,
+ activeCornerRadius = ActiveIconCornerRadius,
+ label = "QSTileCornerRadius",
+ )
+ }
+
+ @Composable
+ fun animateTileShape(state: Int): Shape {
+ return animateShape(
+ state = state,
+ activeCornerRadius = ActiveTileCornerRadius,
+ label = "QSTileIconCornerRadius",
+ )
+ }
+
+ @Composable
+ fun animateShape(state: Int, activeCornerRadius: Dp, label: String): Shape {
+ val animatedCornerRadius by
+ animateDpAsState(
+ targetValue =
+ if (state == STATE_ACTIVE) {
+ activeCornerRadius
+ } else {
+ InactiveCornerRadius
+ },
+ label = label,
+ )
+ return RoundedCornerShape(animatedCornerRadius)
+ }
+}
+
+/**
+ * A composable function that returns the [Resources]. It will be recomposed when [Configuration]
+ * gets updated.
+ */
+@Composable
+@ReadOnlyComposable
+private fun resources(): Resources {
+ LocalConfiguration.current
+ return LocalContext.current.resources
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
index 08ee856..b16a707 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
@@ -24,7 +24,7 @@
import com.android.systemui.qs.shared.model.CategoryAndName
/** Represents an item from a grid associated with a row and a span */
-interface GridCell {
+sealed interface GridCell {
val row: Int
val span: GridItemSpan
}
@@ -38,30 +38,26 @@
override val tile: EditTileViewModel,
override val row: Int,
override val width: Int,
- override val span: GridItemSpan = GridItemSpan(width)
+ override val span: GridItemSpan = GridItemSpan(width),
) : GridCell, SizedTile<EditTileViewModel>, CategoryAndName by tile {
val key: String = "${tile.tileSpec.spec}-$row"
constructor(
sizedTile: SizedTile<EditTileViewModel>,
- row: Int
- ) : this(
- tile = sizedTile.tile,
- row = row,
- width = sizedTile.width,
- )
+ row: Int,
+ ) : this(tile = sizedTile.tile, row = row, width = sizedTile.width)
}
/** Represents an empty space used to fill incomplete rows. Will always display as a 1x1 tile */
@Immutable
data class SpacerGridCell(
override val row: Int,
- override val span: GridItemSpan = GridItemSpan(1)
+ override val span: GridItemSpan = GridItemSpan(1),
) : GridCell
fun List<SizedTile<EditTileViewModel>>.toGridCells(
columns: Int,
- includeSpacers: Boolean = false
+ includeSpacers: Boolean = false,
): List<GridCell> {
return splitInRowsSequence(this, columns)
.flatMapIndexed { rowIndex, sizedTiles ->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
index 45051fe..aa42080 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileUiState.kt
@@ -16,8 +16,16 @@
package com.android.systemui.qs.panels.ui.viewmodel
+import android.content.res.Resources
+import android.service.quicksettings.Tile
+import android.text.TextUtils
+import android.widget.Switch
import androidx.compose.runtime.Immutable
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.state.ToggleableState
import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.tileimpl.SubtitleArrayMapping
+import com.android.systemui.res.R
import java.util.function.Supplier
@Immutable
@@ -27,14 +35,78 @@
val state: Int,
val handlesSecondaryClick: Boolean,
val icon: Supplier<QSTile.Icon?>,
+ val accessibilityUiState: AccessibilityUiState,
)
-fun QSTile.State.toUiState(): TileUiState {
+data class AccessibilityUiState(
+ val contentDescription: String,
+ val stateDescription: String,
+ val accessibilityRole: Role,
+ val toggleableState: ToggleableState? = null,
+ val clickLabel: String? = null,
+)
+
+fun QSTile.State.toUiState(resources: Resources): TileUiState {
+ val accessibilityRole =
+ if (expandedAccessibilityClassName == Switch::class.java.name && !handlesSecondaryClick) {
+ Role.Switch
+ } else {
+ Role.Button
+ }
+ // State handling and description
+ val stateDescription = StringBuilder()
+ val stateText =
+ if (accessibilityRole == Role.Switch || state == Tile.STATE_UNAVAILABLE) {
+ getStateText(resources)
+ } else {
+ ""
+ }
+ val secondaryLabel = getSecondaryLabel(stateText)
+ if (!TextUtils.isEmpty(stateText)) {
+ stateDescription.append(stateText)
+ }
+ if (disabledByPolicy && state != Tile.STATE_UNAVAILABLE) {
+ stateDescription.append(", ")
+ stateDescription.append(getUnavailableText(spec, resources))
+ }
+ if (
+ !TextUtils.isEmpty(this.stateDescription) &&
+ !stateDescription.contains(this.stateDescription!!)
+ ) {
+ stateDescription.append(", ")
+ stateDescription.append(this.stateDescription)
+ }
+ val toggleableState =
+ if (accessibilityRole == Role.Switch || handlesSecondaryClick) {
+ ToggleableState(state == Tile.STATE_ACTIVE)
+ } else {
+ null
+ }
return TileUiState(
- label?.toString() ?: "",
- secondaryLabel?.toString() ?: "",
- state,
- handlesSecondaryClick,
- icon?.let { Supplier { icon } } ?: iconSupplier ?: Supplier { null },
+ label = label?.toString() ?: "",
+ secondaryLabel = secondaryLabel?.toString() ?: "",
+ state = if (disabledByPolicy) Tile.STATE_UNAVAILABLE else state,
+ handlesSecondaryClick = handlesSecondaryClick,
+ icon = icon?.let { Supplier { icon } } ?: iconSupplier ?: Supplier { null },
+ AccessibilityUiState(
+ contentDescription?.toString() ?: "",
+ stateDescription.toString(),
+ accessibilityRole,
+ toggleableState,
+ resources
+ .getString(R.string.accessibility_tile_disabled_by_policy_action_description)
+ .takeIf { disabledByPolicy },
+ ),
)
}
+
+private fun QSTile.State.getStateText(resources: Resources): CharSequence {
+ val arrayResId = SubtitleArrayMapping.getSubtitleId(spec)
+ val array = resources.getStringArray(arrayResId)
+ return array[state]
+}
+
+private fun getUnavailableText(spec: String?, resources: Resources): String {
+ val arrayResId = SubtitleArrayMapping.getSubtitleId(spec)
+ return resources.getStringArray(arrayResId)[Tile.STATE_UNAVAILABLE]
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt
index 0bcb6b7..9677d47 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt
@@ -18,8 +18,6 @@
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.qs.flags.NewQsUI
-import com.android.systemui.qs.panels.domain.interactor.GridConsistencyInteractor
import com.android.systemui.qs.pipeline.domain.interactor.AccessibilityTilesInteractor
import com.android.systemui.qs.pipeline.domain.interactor.AutoAddInteractor
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
@@ -36,16 +34,11 @@
private val autoAddInteractor: AutoAddInteractor,
private val featureFlags: QSPipelineFlagsRepository,
private val restoreReconciliationInteractor: RestoreReconciliationInteractor,
- private val gridConsistencyInteractor: GridConsistencyInteractor,
) : CoreStartable {
override fun start() {
accessibilityTilesInteractor.init(currentTilesInteractor)
autoAddInteractor.init(currentTilesInteractor)
restoreReconciliationInteractor.start()
-
- if (NewQsUI.isEnabled) {
- gridConsistencyInteractor.start()
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 7ceb786..7bff827 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -32,7 +32,7 @@
import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.util.Log;
-import android.widget.Switch;
+import android.widget.Button;
import androidx.annotation.VisibleForTesting;
@@ -59,13 +59,13 @@
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.BluetoothController;
-import kotlinx.coroutines.Job;
-
import java.util.List;
import java.util.concurrent.Executor;
import javax.inject.Inject;
+import kotlinx.coroutines.Job;
+
/** Quick settings tile: Bluetooth **/
public class BluetoothTile extends QSTileImpl<BooleanState> {
@@ -147,6 +147,8 @@
}
}
+
+
@Override
public Intent getLongClickIntent() {
return new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
@@ -221,7 +223,7 @@
state.state = Tile.STATE_INACTIVE;
}
- state.expandedAccessibilityClassName = Switch.class.getName();
+ state.expandedAccessibilityClassName = Button.class.getName();
state.forceExpandIcon = mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index b927134..a4fe4e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -49,7 +49,7 @@
import com.android.systemui.animation.Expandable;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.RefactorFlagUtils;
+import com.android.systemui.modes.shared.ModesUi;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -108,8 +108,7 @@
statusBarStateController, activityStarter, qsLogger);
// If the flag is on, this shouldn't run at all since the modes tile replaces the DND tile.
- RefactorFlagUtils.INSTANCE.assertInLegacyMode(android.app.Flags.modesUi(),
- android.app.Flags.FLAG_MODES_UI);
+ ModesUi.assertInLegacyMode();
mController = zenModeController;
mSharedPreferences = sharedPreferences;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 078698c..7606293 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -55,7 +55,7 @@
qsLogger: QSLogger,
private val keyguardStateController: KeyguardStateController,
private val dialogTransitionAnimator: DialogTransitionAnimator,
- private val fontScalingDialogDelegateProvider: Provider<FontScalingDialogDelegate>
+ private val fontScalingDialogDelegateProvider: Provider<FontScalingDialogDelegate>,
) :
QSTileImpl<QSTile.State?>(
host,
@@ -66,7 +66,7 @@
metricsLogger,
statusBarStateController,
activityStarter,
- qsLogger
+ qsLogger,
) {
private val icon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
@@ -86,7 +86,7 @@
expandable?.dialogTransitionController(
DialogCuj(
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
- INTERACTION_JANK_TAG
+ INTERACTION_JANK_TAG,
)
)
controller?.let { dialogTransitionAnimator.show(dialog, controller) }
@@ -102,7 +102,7 @@
/* cancelAction= */ null,
/* dismissShade= */ true,
/* afterKeyguardGone= */ true,
- /* deferred= */ false
+ /* deferred= */ false,
)
}
}
@@ -110,6 +110,7 @@
override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
state?.label = mContext.getString(R.string.quick_settings_font_scaling_label)
state?.icon = icon
+ state?.contentDescription = state?.label
}
override fun getLongClickIntent(): Intent? {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
index 7d23fbd..cf2db6c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
@@ -16,7 +16,6 @@
package com.android.systemui.qs.tiles
-import android.app.Flags
import android.content.Intent
import android.os.Handler
import android.os.Looper
@@ -30,7 +29,8 @@
import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.RefactorFlagUtils.isUnexpectedlyInLegacyMode
+import com.android.systemui.modes.shared.ModesUi
+import com.android.systemui.modes.shared.ModesUiIcons
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.qs.QSTile
@@ -77,14 +77,14 @@
metricsLogger,
statusBarStateController,
activityStarter,
- qsLogger
+ qsLogger,
) {
private lateinit var tileState: QSTileState
private val config = qsTileConfigProvider.getConfig(TILE_SPEC)
init {
- /* Check if */ isUnexpectedlyInLegacyMode(Flags.modesUi(), Flags.FLAG_MODES_UI)
+ /* Check if */ ModesUiIcons.isUnexpectedlyInLegacyMode()
lifecycle.coroutineScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
@@ -93,7 +93,7 @@
}
}
- override fun isAvailable(): Boolean = Flags.modesUi()
+ override fun isAvailable(): Boolean = ModesUi.isEnabled
override fun getTileLabel(): CharSequence = tileState.label
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index 483373d..5d44ead 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -16,13 +16,14 @@
package com.android.systemui.qs.tiles.impl.modes.domain.interactor
-import android.app.Flags
import android.content.Context
import android.os.UserHandle
import com.android.app.tracing.coroutines.flow.map
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.asIcon
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.modes.shared.ModesUi
+import com.android.systemui.modes.shared.ModesUiIcons
import com.android.systemui.qs.tiles.ModesTile
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
@@ -47,7 +48,7 @@
override fun tileData(
user: UserHandle,
- triggers: Flow<DataUpdateTrigger>
+ triggers: Flow<DataUpdateTrigger>,
): Flow<ModesTileModel> = tileData()
/**
@@ -64,20 +65,20 @@
suspend fun getCurrentTileModel() = buildTileData(zenModeInteractor.getActiveModes())
private fun buildTileData(activeModes: ActiveZenModes): ModesTileModel {
- if (usesModeIcons()) {
+ if (ModesUiIcons.isEnabled) {
val tileIcon = getTileIcon(activeModes.mainMode)
return ModesTileModel(
isActivated = activeModes.isAnyActive(),
icon = tileIcon.icon,
iconResId = tileIcon.resId,
- activeModes = activeModes.modeNames
+ activeModes = activeModes.modeNames,
)
} else {
return ModesTileModel(
isActivated = activeModes.isAnyActive(),
icon = context.getDrawable(ModesTile.ICON_RES_ID)!!.asIcon(),
iconResId = ModesTile.ICON_RES_ID,
- activeModes = activeModes.modeNames
+ activeModes = activeModes.modeNames,
)
}
}
@@ -97,7 +98,5 @@
}
}
- override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi())
-
- private fun usesModeIcons() = Flags.modesApi() && Flags.modesUi() && Flags.modesUiIcons()
+ override fun availability(user: UserHandle): Flow<Boolean> = flowOf(ModesUi.isEnabled)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
index 61c4c8c..31519a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModel.kt
@@ -18,24 +18,41 @@
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.SwipeDirection
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
+import com.android.compose.animation.scene.UserActionResult.HideOverlay
+import com.android.compose.animation.scene.UserActionResult.ReplaceByOverlay
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.ui.viewmodel.SceneContainerEdge
import com.android.systemui.scene.ui.viewmodel.UserActionsViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.flow.map
/** Models the UI state for the user actions for navigating to other scenes or overlays. */
-class QuickSettingsShadeOverlayActionsViewModel @AssistedInject constructor() :
+class QuickSettingsShadeOverlayActionsViewModel
+@AssistedInject
+constructor(private val containerViewModel: QuickSettingsContainerViewModel) :
UserActionsViewModel() {
override suspend fun hydrateActions(setActions: (Map<UserAction, UserActionResult>) -> Unit) {
- setActions(
- buildMap {
- put(Swipe.Up, UserActionResult.HideOverlay(Overlays.QuickSettingsShade))
- put(Back, UserActionResult.HideOverlay(Overlays.QuickSettingsShade))
+ containerViewModel.editModeViewModel.isEditing
+ .map { isEditing ->
+ buildMap {
+ put(Swipe.Up, HideOverlay(Overlays.QuickSettingsShade))
+ // When editing, back should go back to QS from edit mode (i.e. remain in the
+ // same overlay).
+ if (!isEditing) {
+ put(Back, HideOverlay(Overlays.QuickSettingsShade))
+ }
+ put(
+ Swipe(SwipeDirection.Down, fromSource = SceneContainerEdge.TopLeft),
+ ReplaceByOverlay(Overlays.NotificationsShade),
+ )
+ }
}
- )
+ .collect { actions -> setActions(actions) }
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index 1aa982f..e441a23 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -22,8 +22,6 @@
import com.android.systemui.scene.domain.SceneDomainModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule
import com.android.systemui.scene.domain.startable.KeyguardStateCallbackStartable
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
@@ -47,7 +45,6 @@
EmptySceneModule::class,
GoneSceneModule::class,
NotificationsShadeOverlayModule::class,
- NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
QuickSettingsShadeOverlayModule::class,
QuickSettingsSceneModule::class,
@@ -56,8 +53,6 @@
// List SceneResolver modules for supported SceneFamilies
HomeSceneFamilyResolverModule::class,
- NotifShadeSceneFamilyResolverModule::class,
- QuickSettingsSceneFamilyResolverModule::class,
]
)
interface KeyguardlessSceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 7f0cf86..a89f752 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -22,8 +22,6 @@
import com.android.systemui.scene.domain.SceneDomainModule
import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
import com.android.systemui.scene.domain.resolver.HomeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.NotifShadeSceneFamilyResolverModule
-import com.android.systemui.scene.domain.resolver.QuickSettingsSceneFamilyResolverModule
import com.android.systemui.scene.domain.startable.KeyguardStateCallbackStartable
import com.android.systemui.scene.domain.startable.SceneContainerStartable
import com.android.systemui.scene.domain.startable.ScrimStartable
@@ -52,16 +50,12 @@
QuickSettingsSceneModule::class,
ShadeSceneModule::class,
QuickSettingsShadeOverlayModule::class,
- QuickSettingsShadeSceneModule::class,
NotificationsShadeOverlayModule::class,
- NotificationsShadeSceneModule::class,
NotificationsShadeSessionModule::class,
SceneDomainModule::class,
// List SceneResolver modules for supported SceneFamilies
HomeSceneFamilyResolverModule::class,
- NotifShadeSceneFamilyResolverModule::class,
- QuickSettingsSceneFamilyResolverModule::class,
]
)
interface SceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
index 429b47b..667827a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
@@ -16,13 +16,14 @@
package com.android.systemui.scene.domain.interactor
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardOcclusionInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -117,28 +118,30 @@
private val ObservableTransitionState.canBeOccluded: Boolean
get() =
when (this) {
- is ObservableTransitionState.Idle -> currentScene.canBeOccluded
- is ObservableTransitionState.Transition.ChangeScene ->
- fromScene.canBeOccluded && toScene.canBeOccluded
- is ObservableTransitionState.Transition.ReplaceOverlay,
- is ObservableTransitionState.Transition.ShowOrHideOverlay ->
- TODO("b/359173565: Handle overlay transitions")
+ is ObservableTransitionState.Idle ->
+ currentOverlays.all { it.canBeOccluded } && currentScene.canBeOccluded
+ is ObservableTransitionState.Transition ->
+ // TODO(b/356596436): Should also verify currentOverlays.isEmpty(), but
+ // currentOverlays is a Flow and we need a state.
+ fromContent.canBeOccluded && toContent.canBeOccluded
}
/**
- * Whether the scene can be occluded by a "show when locked" activity. Some scenes should, on
+ * Whether the content can be occluded by a "show when locked" activity. Some content should, on
* principle not be occlude-able because they render as if they are expanding on top of the
* occluding activity.
*/
- private val SceneKey.canBeOccluded: Boolean
+ private val ContentKey.canBeOccluded: Boolean
get() =
when (this) {
+ Overlays.NotificationsShade -> false
+ Overlays.QuickSettingsShade -> false
Scenes.Bouncer -> false
Scenes.Communal -> true
Scenes.Gone -> true
Scenes.Lockscreen -> true
Scenes.QuickSettings -> false
Scenes.Shade -> false
- else -> error("SceneKey \"$this\" doesn't have a mapping for canBeOccluded!")
+ else -> error("ContentKey \"$this\" doesn't have a mapping for canBeOccluded!")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 0d24adc..f20e5a5 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -120,21 +120,18 @@
)
/**
- * The key of the scene that the UI is currently transitioning to or `null` if there is no
+ * The key of the content that the UI is currently transitioning to or `null` if there is no
* active transition at the moment.
*
* This is a convenience wrapper around [transitionState], meant for flow-challenged consumers
* like Java code.
*/
- val transitioningTo: StateFlow<SceneKey?> =
+ val transitioningTo: StateFlow<ContentKey?> =
transitionState
.map { state ->
when (state) {
is ObservableTransitionState.Idle -> null
- is ObservableTransitionState.Transition.ChangeScene -> state.toScene
- is ObservableTransitionState.Transition.ShowOrHideOverlay,
- is ObservableTransitionState.Transition.ReplaceOverlay ->
- TODO("b/359173565: Handle overlay transitions")
+ is ObservableTransitionState.Transition -> state.toContent
}
}
.stateIn(
@@ -160,15 +157,14 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = false
+ initialValue = false,
)
/** Whether the scene container is visible. */
val isVisible: StateFlow<Boolean> =
- combine(
- repository.isVisible,
- repository.isRemoteUserInputOngoing,
- ) { isVisible, isRemoteUserInteractionOngoing ->
+ combine(repository.isVisible, repository.isRemoteUserInputOngoing) {
+ isVisible,
+ isRemoteUserInteractionOngoing ->
isVisibleInternal(
raw = isVisible,
isRemoteUserInputOngoing = isRemoteUserInteractionOngoing,
@@ -177,7 +173,7 @@
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = isVisibleInternal()
+ initialValue = isVisibleInternal(),
)
/** Whether there's an ongoing remotely-initiated user interaction. */
@@ -259,10 +255,7 @@
* The change is instantaneous and not animated; it will be observable in the next frame and
* there will be no transition animation.
*/
- fun snapToScene(
- toScene: SceneKey,
- loggingReason: String,
- ) {
+ fun snapToScene(toScene: SceneKey, loggingReason: String) {
val currentSceneKey = currentScene.value
val resolvedScene =
sceneFamilyResolvers.get()[toScene]?.let { familyResolver ->
@@ -313,15 +306,9 @@
return
}
- logger.logOverlayChangeRequested(
- to = overlay,
- reason = loggingReason,
- )
+ logger.logOverlayChangeRequested(to = overlay, reason = loggingReason)
- repository.showOverlay(
- overlay = overlay,
- transitionKey = transitionKey,
- )
+ repository.showOverlay(overlay = overlay, transitionKey = transitionKey)
}
/**
@@ -345,15 +332,9 @@
return
}
- logger.logOverlayChangeRequested(
- from = overlay,
- reason = loggingReason,
- )
+ logger.logOverlayChangeRequested(from = overlay, reason = loggingReason)
- repository.hideOverlay(
- overlay = overlay,
- transitionKey = transitionKey,
- )
+ repository.hideOverlay(overlay = overlay, transitionKey = transitionKey)
}
/**
@@ -378,17 +359,9 @@
return
}
- logger.logOverlayChangeRequested(
- from = from,
- to = to,
- reason = loggingReason,
- )
+ logger.logOverlayChangeRequested(from = from, to = to, reason = loggingReason)
- repository.replaceOverlay(
- from = from,
- to = to,
- transitionKey = transitionKey,
- )
+ repository.replaceOverlay(from = from, to = to, transitionKey = transitionKey)
}
/**
@@ -405,11 +378,7 @@
return
}
- logger.logVisibilityChange(
- from = wasVisible,
- to = isVisible,
- reason = loggingReason,
- )
+ logger.logVisibilityChange(from = wasVisible, to = isVisible, reason = loggingReason)
return repository.setVisible(isVisible)
}
@@ -491,11 +460,7 @@
* @param loggingReason The reason why the transition is requested, for logging purposes
* @return `true` if the scene change is valid; `false` if it shouldn't happen
*/
- private fun validateSceneChange(
- from: SceneKey,
- to: SceneKey,
- loggingReason: String,
- ): Boolean {
+ private fun validateSceneChange(from: SceneKey, to: SceneKey, loggingReason: String): Boolean {
if (to !in repository.allContentKeys) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt
deleted file mode 100644
index a313273..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/NotifShadeSceneFamilyResolver.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2024 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.scene.domain.resolver
-
-import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-@SysUISingleton
-class NotifShadeSceneFamilyResolver
-@Inject
-constructor(
- @Application applicationScope: CoroutineScope,
- shadeModeInteractor: ShadeModeInteractor,
-) : SceneResolver {
- override val targetFamily: SceneKey = SceneFamilies.NotifShade
-
- override val resolvedScene: StateFlow<SceneKey> =
- shadeModeInteractor.shadeMode
- .map(::notifShadeScene)
- .stateIn(
- applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = notifShadeScene(shadeModeInteractor.shadeMode.value),
- )
-
- override fun includesScene(scene: SceneKey): Boolean = scene in notifShadeScenes
-
- private fun notifShadeScene(shadeMode: ShadeMode) =
- when (shadeMode) {
- is ShadeMode.Single -> Scenes.Shade
- is ShadeMode.Dual -> Scenes.NotificationsShade
- is ShadeMode.Split -> Scenes.Shade
- }
-
- companion object {
- val notifShadeScenes = setOf(Scenes.NotificationsShade, Scenes.Shade)
- }
-}
-
-@Module
-interface NotifShadeSceneFamilyResolverModule {
- @Binds @IntoSet fun bindResolver(interactor: NotifShadeSceneFamilyResolver): SceneResolver
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt
deleted file mode 100644
index 923e712a..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/QuickSettingsSceneFamilyResolver.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2024 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.scene.domain.resolver
-
-import com.android.compose.animation.scene.SceneKey
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
-import com.android.systemui.shade.shared.model.ShadeMode
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoSet
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-@SysUISingleton
-class QuickSettingsSceneFamilyResolver
-@Inject
-constructor(
- @Application applicationScope: CoroutineScope,
- shadeModeInteractor: ShadeModeInteractor,
-) : SceneResolver {
- override val targetFamily: SceneKey = SceneFamilies.QuickSettings
-
- override val resolvedScene: StateFlow<SceneKey> =
- shadeModeInteractor.shadeMode
- .map(::quickSettingsScene)
- .stateIn(
- applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = quickSettingsScene(shadeModeInteractor.shadeMode.value),
- )
-
- override fun includesScene(scene: SceneKey): Boolean = scene in quickSettingsScenes
-
- private fun quickSettingsScene(shadeMode: ShadeMode) =
- when (shadeMode) {
- is ShadeMode.Single -> Scenes.QuickSettings
- is ShadeMode.Dual -> Scenes.QuickSettingsShade
- is ShadeMode.Split -> Scenes.Shade
- }
-
- companion object {
- val quickSettingsScenes =
- setOf(Scenes.QuickSettings, Scenes.QuickSettingsShade, Scenes.Shade)
- }
-}
-
-@Module
-interface QuickSettingsSceneFamilyResolverModule {
- @Binds @IntoSet fun bindResolver(interactor: QuickSettingsSceneFamilyResolver): SceneResolver
-}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index c5e0ccc..b7e2cf2 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -61,6 +61,7 @@
import com.android.systemui.scene.session.shared.SessionStorage
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.logger.SceneLogger
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -107,6 +108,7 @@
* Hooks up business logic that manipulates the state of the [SceneInteractor] for the system UI
* scene container based on state from other systems.
*/
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class SceneContainerStartable
@Inject
@@ -227,8 +229,10 @@
is ObservableTransitionState.Idle -> {
if (state.currentScene != Scenes.Gone) {
true to "scene is not Gone"
+ } else if (state.currentOverlays.isNotEmpty()) {
+ true to "overlay is shown"
} else {
- false to "scene is Gone"
+ false to "scene is Gone and no overlays are shown"
}
}
is ObservableTransitionState.Transition -> {
@@ -408,8 +412,7 @@
}
isOnPrimaryBouncer -> {
// When the device becomes unlocked in primary Bouncer,
- // notify dismiss succeeded and
- // go to previous scene or Gone.
+ // notify dismiss succeeded and go to previous scene or Gone.
dismissCallbackRegistry.notifyDismissSucceeded()
if (
previousScene.value == Scenes.Lockscreen ||
@@ -596,12 +599,12 @@
combine(
sceneInteractor.transitionState
.mapNotNull { it as? ObservableTransitionState.Idle }
- .map { it.currentScene }
.distinctUntilChanged(),
occlusionInteractor.invisibleDueToOcclusion,
- ) { sceneKey, invisibleDueToOcclusion ->
+ ) { idleState, invisibleDueToOcclusion ->
SceneContainerPlugin.SceneContainerPluginState(
- scene = sceneKey,
+ scene = idleState.currentScene,
+ overlays = idleState.currentOverlays,
invisibleDueToOcclusion = invisibleDueToOcclusion,
)
}
@@ -712,19 +715,21 @@
if (isDeviceLocked) {
sceneInteractor.transitionState
.mapNotNull { it as? ObservableTransitionState.Idle }
- .map { it.currentScene }
+ .map { it.currentScene to it.currentOverlays }
.distinctUntilChanged()
- .map { sceneKey ->
- when (sceneKey) {
+ .map { (sceneKey, currentOverlays) ->
+ when {
// When locked, showing the lockscreen scene should be reported
// as "interacting" while showing other scenes should report as
// "not interacting".
//
// This is done here in order to match the legacy
// implementation. The real reason why is lost to lore and myth.
- Scenes.Lockscreen -> true
- Scenes.Bouncer -> false
- Scenes.Shade -> false
+ Overlays.NotificationsShade in currentOverlays -> false
+ Overlays.QuickSettingsShade in currentOverlays -> null
+ sceneKey == Scenes.Lockscreen -> true
+ sceneKey == Scenes.Bouncer -> false
+ sceneKey == Scenes.Shade -> false
else -> null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
index 751448f..7b6b0f6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
@@ -26,7 +26,6 @@
import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
import com.android.systemui.keyguard.KeyguardWmStateRefactor
import com.android.systemui.keyguard.MigrateClocksToBlueprint
-import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.phone.PredictiveBackSysUiFlag
@@ -39,7 +38,6 @@
inline val isEnabled
get() =
sceneContainer() && // mainAconfigFlag
- ComposeLockscreen.isEnabled &&
KeyguardBottomAreaRefactor.isEnabled &&
KeyguardWmStateRefactor.isEnabled &&
MigrateClocksToBlueprint.isEnabled &&
@@ -55,7 +53,6 @@
/** The set of secondary flags which must be enabled for scene container to work properly */
inline fun getSecondaryFlags(): Sequence<FlagToken> =
sequenceOf(
- ComposeLockscreen.token,
KeyguardBottomAreaRefactor.token,
KeyguardWmStateRefactor.token,
MigrateClocksToBlueprint.token,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
index 115d664..82b4b1c 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
@@ -43,22 +43,6 @@
@JvmField val Lockscreen = SceneKey("lockscreen")
/**
- * The notifications shade scene primarily shows a scrollable list of notifications as an
- * overlay UI.
- *
- * It's used only in the dual shade configuration, where there are two separate shades: one for
- * notifications (this scene) and another for [QuickSettingsShade].
- *
- * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
- * swipe down again the to expand quick settings) or in the "split" shade configuration (on
- * large screens or unfolded foldables, where notifications and quick settings are shown
- * side-by-side in their own columns).
- */
- @Deprecated("The notifications shade scene has been replaced by an overlay")
- @JvmField
- val NotificationsShade = SceneKey("notifications_shade")
-
- /**
* The quick settings scene shows the quick setting tiles.
*
* This scene is used for single/accordion configuration (swipe down once to reveal the shade,
@@ -69,27 +53,12 @@
* scene is used.
*
* For the dual shade configuration, where there are two separate shades: one for notifications
- * and one for quick settings, [NotificationsShade] and [QuickSettingsShade] scenes are used
- * respectively.
+ * and one for quick settings, the overlays `NotificationsShade` and `QuickSettingsShade` are
+ * used respectively.
*/
@JvmField val QuickSettings = SceneKey("quick_settings")
/**
- * The quick settings shade scene shows the quick setting tiles as an overlay UI.
- *
- * It's used only in the dual shade configuration, where there are two separate shades: one for
- * quick settings (this scene) and another for [NotificationsShade].
- *
- * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
- * swipe down again the to expand quick settings) or in the "split" shade configuration (on
- * large screens or unfolded foldables, where notifications and quick settings are shown
- * side-by-side in their own columns).
- */
- @Deprecated("The quick settings shade scene has been replaced by an overlay")
- @JvmField
- val QuickSettingsShade = SceneKey("quick_settings_shade")
-
- /**
* The shade is the scene that shows a scrollable list of notifications and the minimized
* version of quick settings (AKA "quick quick settings" or "QQS").
*
@@ -97,7 +66,8 @@
* swipe down again the to expand quick settings) and for the "split" shade configuration (on
* large screens or unfolded foldables, where notifications and quick settings are shown
* side-by-side in their own columns). For the dual shade configuration, where there are two
- * separate shades: one for notifications and one for quick settings, other scenes are used.
+ * separate shades: one for notifications and one for quick settings, the overlays
+ * `NotificationsShade` and `QuickSettingsShade` are used respectively.
*/
@JvmField val Shade = SceneKey("shade")
}
@@ -114,16 +84,4 @@
* depending on whether the device is unlocked and has been entered.
*/
@JvmField val Home = SceneKey(debugName = "scene_family_home")
-
- /**
- * The scene that contains the full, interactive notification shade. The specific scene it
- * resolves to can depend on dual / split / single shade settings.
- */
- @JvmField val NotifShade = SceneKey(debugName = "scene_family_notif_shade")
-
- /**
- * The scene that contains the full QuickSettings (not to be confused with Quick-QuickSettings).
- * The specific scene it resolves to can depend on dual / split / single shade settings.
- */
- @JvmField val QuickSettings = SceneKey(debugName = "scene_family_quick_settings")
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModel.kt
index 7bf2b63..5ff507a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModel.kt
@@ -19,7 +19,6 @@
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.SwipeDirection
-import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.scene.shared.model.Overlays
@@ -38,21 +37,25 @@
shadeInteractor.shadeMode.collect { shadeMode ->
setActions(
when (shadeMode) {
- ShadeMode.Single -> fullscreenShadeActions()
- ShadeMode.Split -> fullscreenShadeActions(transitionKey = ToSplitShade)
+ ShadeMode.Single -> singleShadeActions()
+ ShadeMode.Split -> splitShadeActions()
ShadeMode.Dual -> dualShadeActions()
}
)
}
}
- private fun fullscreenShadeActions(
- transitionKey: TransitionKey? = null
- ): Map<UserAction, UserActionResult> {
+ private fun singleShadeActions(): Map<UserAction, UserActionResult> {
return mapOf(
- Swipe.Down to UserActionResult(Scenes.Shade, transitionKey),
- Swipe(direction = SwipeDirection.Down, pointerCount = 2, fromSource = Edge.Top) to
- UserActionResult(Scenes.Shade, transitionKey),
+ Swipe.Down to Scenes.Shade,
+ swipeDownFromTopWithTwoFingers() to Scenes.QuickSettings,
+ )
+ }
+
+ private fun splitShadeActions(): Map<UserAction, UserActionResult> {
+ return mapOf(
+ Swipe.Down to UserActionResult(Scenes.Shade, ToSplitShade),
+ swipeDownFromTopWithTwoFingers() to UserActionResult(Scenes.Shade, ToSplitShade),
)
}
@@ -64,6 +67,10 @@
)
}
+ private fun swipeDownFromTopWithTwoFingers(): UserAction {
+ return Swipe(direction = SwipeDirection.Down, pointerCount = 2, fromSource = Edge.Top)
+ }
+
@AssistedFactory
interface Factory {
fun create(): GoneUserActionsViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index c451704..af1f5a7 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -52,7 +52,7 @@
private val sceneInteractor: SceneInteractor,
private val falsingInteractor: FalsingInteractor,
private val powerInteractor: PowerInteractor,
- private val shadeInteractor: ShadeInteractor,
+ shadeInteractor: ShadeInteractor,
private val splitEdgeDetector: SplitEdgeDetector,
private val logger: SceneLogger,
@Assisted private val motionEventHandlerReceiver: (MotionEventHandler?) -> Unit,
@@ -212,9 +212,10 @@
)
}
}
+ // Overlay transitions don't use scene families, nothing to resolve.
is UserActionResult.ShowOverlay,
is UserActionResult.HideOverlay,
- is UserActionResult.ReplaceByOverlay -> TODO("b/353679003: Support overlays")
+ is UserActionResult.ReplaceByOverlay -> null
} ?: actionResult
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
index b9f9b92..05f19ef 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/MultiUserUtilsModule.java
@@ -16,6 +16,7 @@
package com.android.systemui.settings;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.hardware.display.DisplayManager;
@@ -66,7 +67,7 @@
@Background CoroutineDispatcher backgroundDispatcher,
@Background Handler handler
) {
- int startingUser = userManager.getBootUser().getIdentifier();
+ int startingUser = ActivityManager.getCurrentUser();
UserTrackerImpl tracker = new UserTrackerImpl(context, featureFlagsProvider, userManager,
iActivityManager, dumpManager, appScope, backgroundDispatcher, handler);
tracker.initialize(startingUser);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
index 1a997a7..e1631cc 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -16,11 +16,10 @@
package com.android.systemui.settings
-import com.android.systemui.util.annotations.WeaklyReferencedCallback
-
import android.content.Context
import android.content.pm.UserInfo
import android.os.UserHandle
+import com.android.systemui.util.annotations.WeaklyReferencedCallback
import java.util.concurrent.Executor
/**
@@ -31,19 +30,13 @@
*/
interface UserTracker : UserContentResolverProvider, UserContextProvider {
- /**
- * Current user's id.
- */
+ /** Current user's id. */
val userId: Int
- /**
- * [UserHandle] for current user
- */
+ /** [UserHandle] for current user */
val userHandle: UserHandle
- /**
- * [UserInfo] for current user
- */
+ /** [UserInfo] for current user */
val userInfo: UserInfo
/**
@@ -56,39 +49,33 @@
*/
val userProfiles: List<UserInfo>
- /**
- * Add a [Callback] to be notified of chances, on a particular [Executor]
- */
+ /** Is the system in the process of switching users? */
+ val isUserSwitching: Boolean
+
+ /** Add a [Callback] to be notified of chances, on a particular [Executor] */
fun addCallback(callback: Callback, executor: Executor)
- /**
- * Remove a [Callback] previously added.
- */
+ /** Remove a [Callback] previously added. */
fun removeCallback(callback: Callback)
- /**
- * Callback for notifying of changes.
- */
+ /** Callback for notifying of changes. */
@WeaklyReferencedCallback
interface Callback {
- /**
- * Notifies that the current user will be changed.
- */
+ /** Notifies that the current user will be changed. */
fun onBeforeUserSwitching(newUser: Int) {}
/**
- * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be
- * called automatically after the completion of this method.
+ * Same as {@link onUserChanging(Int, Context, Runnable)} but the callback will be called
+ * automatically after the completion of this method.
*/
fun onUserChanging(newUser: Int, userContext: Context) {}
/**
- * Notifies that the current user is being changed.
- * Override this method to run things while the screen is frozen for the user switch.
- * Please use {@link #onUserChanged} if the task doesn't need to push the unfreezing of the
- * screen further. Please be aware that code executed in this callback will lengthen the
- * user switch duration. When overriding this method, resultCallback#run() MUST be called
- * once the execution is complete.
+ * Notifies that the current user is being changed. Override this method to run things while
+ * the screen is frozen for the user switch. Please use {@link #onUserChanged} if the task
+ * doesn't need to push the unfreezing of the screen further. Please be aware that code
+ * executed in this callback will lengthen the user switch duration. When overriding this
+ * method, resultCallback#run() MUST be called once the execution is complete.
*/
fun onUserChanging(newUser: Int, userContext: Context, resultCallback: Runnable) {
onUserChanging(newUser, userContext)
@@ -96,15 +83,13 @@
}
/**
- * Notifies that the current user has changed.
- * Override this method to run things after the screen is unfrozen for the user switch.
- * Please see {@link #onUserChanging} if you need to hide jank.
+ * Notifies that the current user has changed. Override this method to run things after the
+ * screen is unfrozen for the user switch. Please see {@link #onUserChanging} if you need to
+ * hide jank.
*/
fun onUserChanged(newUser: Int, userContext: Context) {}
- /**
- * Notifies that the current user's profiles have changed.
- */
+ /** Notifies that the current user's profiles have changed. */
fun onProfilesChanged(profiles: List<@JvmSuppressWildcards UserInfo>) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 553d1f5..1863e12 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -106,6 +106,9 @@
override var userInfo: UserInfo by SynchronizedDelegate(UserInfo(context.userId, "", 0))
protected set
+ override var isUserSwitching = false
+ protected set
+
/**
* Returns a [List<UserInfo>] of all profiles associated with the current user.
*
@@ -197,6 +200,7 @@
}
override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
+ isUserSwitching = true
if (isBackgroundUserSwitchEnabled) {
userSwitchingJob?.cancel()
userSwitchingJob =
@@ -210,6 +214,7 @@
}
override fun onUserSwitchComplete(newUserId: Int) {
+ isUserSwitching = false
if (isBackgroundUserSwitchEnabled) {
afterUserSwitchingJob?.cancel()
afterUserSwitchingJob =
@@ -221,7 +226,7 @@
}
}
},
- TAG
+ TAG,
)
}
@@ -349,7 +354,7 @@
private data class DataItem(
val callback: WeakReference<UserTracker.Callback>,
- val executor: Executor
+ val executor: Executor,
) {
fun sameOrEmpty(other: UserTracker.Callback): Boolean {
return callback.get()?.equals(other) ?: true
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 42499f0..f76c5fd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -137,7 +137,6 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.domain.interactor.NaturalScrollingSettingObserver;
-import com.android.systemui.keyguard.shared.ComposeLockscreen;
import com.android.systemui.keyguard.shared.model.Edge;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -186,6 +185,7 @@
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.HeadsUpTouchHelper;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
@@ -207,7 +207,6 @@
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.notification.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -2511,11 +2510,6 @@
return 0;
}
- if (ComposeLockscreen.isEnabled()) {
- return (int) mKeyguardInteractor.getNotificationContainerBounds()
- .getValue().getTop();
- }
-
if (!mKeyguardBypassController.getBypassEnabled()) {
if (MigrateClocksToBlueprint.isEnabled() && !mSplitShadeEnabled) {
return (int) mKeyguardInteractor.getNotificationContainerBounds()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
index e276f88..cea521f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
@@ -18,10 +18,11 @@
package com.android.systemui.shade.domain.interactor
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.compose.animation.scene.SceneKey
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.SysuiStatusBarStateController
import javax.inject.Inject
@@ -55,7 +56,9 @@
when (state) {
is ObservableTransitionState.Idle ->
flowOf(
- if (state.currentScene != Scenes.Gone) {
+ if (
+ state.currentScene != Scenes.Gone || state.currentOverlays.isNotEmpty()
+ ) {
// When resting on a non-Gone scene, the panel is fully expanded.
1f
} else {
@@ -64,10 +67,10 @@
0f
}
)
- is ObservableTransitionState.Transition.ChangeScene ->
+ is ObservableTransitionState.Transition ->
when {
- state.fromScene == Scenes.Gone ->
- if (state.toScene.isExpandable()) {
+ state.fromContent == Scenes.Gone ->
+ if (state.toContent.isExpandable()) {
// Moving from Gone to a scene that can animate-expand has a
// panel expansion that tracks with the transition.
state.progress
@@ -76,8 +79,8 @@
// immediately makes the panel fully expanded.
flowOf(1f)
}
- state.toScene == Scenes.Gone ->
- if (state.fromScene.isExpandable()) {
+ state.toContent == Scenes.Gone ->
+ if (state.fromContent.isExpandable()) {
// Moving to Gone from a scene that can animate-expand has a
// panel expansion that tracks with the transition.
state.progress.map { 1 - it }
@@ -88,9 +91,6 @@
}
else -> flowOf(1f)
}
- is ObservableTransitionState.Transition.ShowOrHideOverlay,
- is ObservableTransitionState.Transition.ReplaceOverlay ->
- TODO("b/359173565: Handle overlay transitions")
}
}
@@ -132,7 +132,13 @@
return sceneInteractor.currentScene.value == Scenes.Lockscreen
}
- private fun SceneKey.isExpandable(): Boolean {
- return this == Scenes.Shade || this == Scenes.QuickSettings
+ private fun ContentKey.isExpandable(): Boolean {
+ return when (this) {
+ Scenes.Shade,
+ Scenes.QuickSettings,
+ Overlays.NotificationsShade,
+ Overlays.QuickSettingsShade -> true
+ else -> false
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 87f360e..ad3afd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -61,6 +61,7 @@
import com.android.internal.statusbar.StatusBarIcon.Shape;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Flags;
+import com.android.systemui.modes.shared.ModesUiIcons;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.NotificationContentDescription;
import com.android.systemui.statusbar.notification.NotificationDozeHelper;
@@ -215,7 +216,7 @@
// We scale notification icons (on the left) plus icons on the right that explicitly
// want FIXED_SPACE.
boolean useNonSystemIconScaling = isNotification()
- || (usesModeIcons() && mIcon != null && mIcon.shape == Shape.FIXED_SPACE);
+ || (ModesUiIcons.isEnabled() && mIcon != null && mIcon.shape == Shape.FIXED_SPACE);
if (useNonSystemIconScaling) {
updateIconScaleForNonSystemIcons();
@@ -415,7 +416,7 @@
if (!levelEquals) {
setImageLevel(icon.iconLevel);
}
- if (usesModeIcons() && icon.shape == Shape.FIXED_SPACE) {
+ if (ModesUiIcons.isEnabled() && icon.shape == Shape.FIXED_SPACE) {
setScaleType(ScaleType.FIT_CENTER);
}
if (!visibilityEquals) {
@@ -506,7 +507,7 @@
@Nullable
private Drawable loadDrawable(Context context, StatusBarIcon statusBarIcon) {
- if (usesModeIcons() && statusBarIcon.preloadedIcon != null) {
+ if (ModesUiIcons.isEnabled() && statusBarIcon.preloadedIcon != null) {
Drawable.ConstantState cached = statusBarIcon.preloadedIcon.getConstantState();
if (cached != null) {
return cached.newDrawable(mContext.getResources()).mutate();
@@ -1041,9 +1042,4 @@
public boolean showsConversation() {
return mShowsConversation;
}
-
- private static boolean usesModeIcons() {
- return android.app.Flags.modesApi() && android.app.Flags.modesUi()
- && android.app.Flags.modesUiIcons();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
index 718c1c0f..3232684 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
@@ -1,18 +1,7 @@
{
"presubmit": [
{
- "name": "CtsNotificationTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsNotificationTestCases_notification"
}
],
"postsubmit": [
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
index 637cadd..920541d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt
@@ -44,7 +44,7 @@
viewModel,
clearAllNotifications,
launchNotificationSettings,
- launchNotificationHistory
+ launchNotificationHistory,
)
}
}
@@ -55,21 +55,15 @@
viewModel: FooterViewModel,
clearAllNotifications: View.OnClickListener,
launchNotificationSettings: View.OnClickListener,
- launchNotificationHistory: View.OnClickListener
+ launchNotificationHistory: View.OnClickListener,
) = coroutineScope {
- launch {
- bindClearAllButton(
- footer,
- viewModel,
- clearAllNotifications,
- )
- }
+ launch { bindClearAllButton(footer, viewModel, clearAllNotifications) }
launch {
bindManageOrHistoryButton(
footer,
viewModel,
launchNotificationSettings,
- launchNotificationHistory
+ launchNotificationHistory,
)
}
launch { bindMessage(footer, viewModel) }
@@ -80,8 +74,6 @@
viewModel: FooterViewModel,
clearAllNotifications: View.OnClickListener,
) = coroutineScope {
- footer.setClearAllButtonClickListener(clearAllNotifications)
-
launch {
viewModel.clearAllButton.labelId.collect { textId ->
footer.setClearAllButtonText(textId)
@@ -96,18 +88,21 @@
launch {
viewModel.clearAllButton.isVisible.collect { isVisible ->
+ if (isVisible.value) {
+ footer.setClearAllButtonClickListener(clearAllNotifications)
+ } else {
+ // When the button isn't visible, it also shouldn't react to clicks. This is
+ // necessary because when the clear all button is not visible, it's actually
+ // just the alpha that becomes 0 so it can still be tapped.
+ footer.setClearAllButtonClickListener(null)
+ }
+
if (isVisible.isAnimating) {
- footer.setClearAllButtonVisible(
- isVisible.value,
- /* animate = */ true,
- ) { _ ->
+ footer.setClearAllButtonVisible(isVisible.value, /* animate= */ true) { _ ->
isVisible.stopAnimating()
}
} else {
- footer.setClearAllButtonVisible(
- isVisible.value,
- /* animate = */ false,
- )
+ footer.setClearAllButtonVisible(isVisible.value, /* animate= */ false)
}
}
}
@@ -143,22 +138,24 @@
launch {
viewModel.manageOrHistoryButton.isVisible.collect { isVisible ->
- // NOTE: This visibility change is never animated.
+ // NOTE: This visibility change is never animated. We also don't need to do anything
+ // special about the onClickListener here, since we're changing the visibility to
+ // GONE so it won't be clickable anyway.
footer.setManageOrHistoryButtonVisible(isVisible.value)
}
}
}
- private suspend fun bindMessage(
- footer: FooterView,
- viewModel: FooterViewModel,
- ) = coroutineScope {
- // Bind the resource IDs
- footer.setMessageString(viewModel.message.messageId)
- footer.setMessageIcon(viewModel.message.iconId)
+ private suspend fun bindMessage(footer: FooterView, viewModel: FooterViewModel) =
+ coroutineScope {
+ // Bind the resource IDs
+ footer.setMessageString(viewModel.message.messageId)
+ footer.setMessageIcon(viewModel.message.iconId)
- launch {
- viewModel.message.isVisible.collect { visible -> footer.setFooterLabelVisible(visible) }
+ launch {
+ viewModel.message.isVisible.collect { visible ->
+ footer.setFooterLabelVisible(visible)
+ }
+ }
}
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index 3e42413..8d7007b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState.Idle
import com.android.compose.animation.scene.ObservableTransitionState.Transition
import com.android.compose.animation.scene.ObservableTransitionState.Transition.ChangeScene
@@ -26,7 +27,7 @@
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
@@ -46,7 +47,6 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
/** ViewModel which represents the state of the NSSL/Controller in the world of flexiglass */
@@ -91,7 +91,7 @@
): Float {
return if (fullyExpandedDuringSceneChange(change)) {
1f
- } else if (change.isBetween({ it == Scenes.Gone }, { it in SceneFamilies.NotifShade })) {
+ } else if (change.isBetween({ it == Scenes.Gone }, { it == Scenes.Shade })) {
shadeExpansion
} else if (change.isBetween({ it == Scenes.Gone }, { it == Scenes.QuickSettings })) {
// during QS expansion, increase fraction at same rate as scrim alpha,
@@ -99,6 +99,22 @@
(qsExpansion / EXPANSION_FOR_MAX_SCRIM_ALPHA - EXPANSION_FOR_DELAYED_STACK_FADE_IN)
.coerceIn(0f, 1f)
} else {
+ // TODO(b/356596436): If notification shade overlay is open, we'll reach this point and
+ // the expansion fraction in that case should be `shadeExpansion`.
+ 0f
+ }
+ }
+
+ private fun expandFractionDuringOverlayTransition(
+ transition: Transition,
+ currentScene: SceneKey,
+ shadeExpansion: Float,
+ ): Float {
+ return if (currentScene == Scenes.Lockscreen) {
+ 1f
+ } else if (transition.isTransitioningFromOrTo(Overlays.NotificationsShade)) {
+ shadeExpansion
+ } else {
0f
}
}
@@ -114,18 +130,35 @@
shadeInteractor.shadeMode,
shadeInteractor.qsExpansion,
sceneInteractor.transitionState,
- sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings),
- ) { shadeExpansion, _, qsExpansion, transitionState, _ ->
+ ) { shadeExpansion, _, qsExpansion, transitionState ->
when (transitionState) {
- is Idle -> if (expandedInScene(transitionState.currentScene)) 1f else 0f
+ is Idle ->
+ if (
+ expandedInScene(transitionState.currentScene) ||
+ Overlays.NotificationsShade in transitionState.currentOverlays
+ ) {
+ 1f
+ } else {
+ 0f
+ }
is ChangeScene ->
expandFractionDuringSceneChange(
- transitionState,
- shadeExpansion,
- qsExpansion,
+ change = transitionState,
+ shadeExpansion = shadeExpansion,
+ qsExpansion = qsExpansion,
)
- is Transition.ShowOrHideOverlay,
- is Transition.ReplaceOverlay -> TODO("b/359173565: Handle overlay transitions")
+ is Transition.ShowOrHideOverlay ->
+ expandFractionDuringOverlayTransition(
+ transition = transitionState,
+ currentScene = transitionState.currentScene,
+ shadeExpansion = shadeExpansion,
+ )
+ is Transition.ReplaceOverlay ->
+ expandFractionDuringOverlayTransition(
+ transition = transitionState,
+ currentScene = transitionState.currentScene,
+ shadeExpansion = shadeExpansion,
+ )
}
}
.distinctUntilChanged()
@@ -166,14 +199,14 @@
fun shadeScrimShape(
cornerRadius: Flow<Int>,
- viewLeftOffset: Flow<Int>
+ viewLeftOffset: Flow<Int>,
): Flow<ShadeScrimShape?> =
combine(shadeScrimClipping, cornerRadius, viewLeftOffset) { clipping, radius, leftOffset ->
if (clipping == null) return@combine null
ShadeScrimShape(
bounds = clipping.bounds.minus(leftOffset = leftOffset),
topRadius = radius.takeIf { clipping.rounding.isTopRounded } ?: 0,
- bottomRadius = radius.takeIf { clipping.rounding.isBottomRounded } ?: 0
+ bottomRadius = radius.takeIf { clipping.rounding.isBottomRounded } ?: 0,
)
}
.dumpWhileCollecting("shadeScrimShape")
@@ -209,10 +242,10 @@
/** Whether the notification stack is scrollable or not. */
val isScrollable: Flow<Boolean> =
- sceneInteractor.currentScene
- .map {
- sceneInteractor.isSceneInFamily(it, SceneFamilies.NotifShade) ||
- it == Scenes.Lockscreen
+ combine(sceneInteractor.currentScene, sceneInteractor.currentOverlays) {
+ currentScene,
+ currentOverlays ->
+ currentScene.showsNotifications() || currentOverlays.any { it.showsNotifications() }
}
.dumpWhileCollecting("isScrollable")
@@ -242,13 +275,20 @@
}
}
+ private fun ContentKey.showsNotifications(): Boolean {
+ return when (this) {
+ Overlays.NotificationsShade,
+ Scenes.Lockscreen,
+ Scenes.Shade -> true
+ else -> false
+ }
+ }
+
@AssistedFactory
interface Factory {
fun create(): NotificationScrollViewModel
}
}
-private fun ChangeScene.isBetween(
- a: (SceneKey) -> Boolean,
- b: (SceneKey) -> Boolean,
-): Boolean = (a(fromScene) && b(toScene)) || (b(fromScene) && a(toScene))
+private fun ChangeScene.isBetween(a: (SceneKey) -> Boolean, b: (SceneKey) -> Boolean): Boolean =
+ (a(fromScene) && b(toScene)) || (b(fromScene) && a(toScene))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index ba39c3b..8c03538 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -51,6 +51,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor;
+import com.android.systemui.modes.shared.ModesUiIcons;
import com.android.systemui.privacy.PrivacyItem;
import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.privacy.PrivacyType;
@@ -360,7 +361,7 @@
mBluetooth.addCallback(this);
mProvisionedController.addCallback(this);
mCurrentUserSetup = mProvisionedController.isCurrentUserSetup();
- if (usesModeIcons()) {
+ if (ModesUiIcons.isEnabled()) {
// Note that we're not fully replacing ZenModeController with ZenModeInteractor, so
// we listen for the extra event here but still add the ZMC callback.
mJavaAdapter.alwaysCollectFlow(mZenModeInteractor.getMainActiveMode(),
@@ -397,8 +398,7 @@
}
private void onMainActiveModeChanged(@Nullable ZenModeInfo mainActiveMode) {
- if (!usesModeIcons()) {
- Log.wtf(TAG, "onMainActiveModeChanged shouldn't run if MODES_UI_ICONS is disabled");
+ if (ModesUiIcons.isUnexpectedlyInLegacyMode()) {
return;
}
@@ -458,14 +458,14 @@
private void updateVolumeZen() {
int zen = mZenController.getZen();
- if (!usesModeIcons()) {
+ if (!ModesUiIcons.isEnabled()) {
updateZenIcon(zen);
}
updateRingerAndAlarmIcons(zen);
}
private void updateZenIcon(int zen) {
- if (usesModeIcons()) {
+ if (ModesUiIcons.isEnabled()) {
Log.wtf(TAG, "updateZenIcon shouldn't be called if MODES_UI_ICONS is enabled");
return;
}
@@ -942,9 +942,4 @@
mIconController.setIconVisibility(mSlotConnectedDisplay, visible);
}
-
- private static boolean usesModeIcons() {
- return android.app.Flags.modesApi() && android.app.Flags.modesUi()
- && android.app.Flags.modesUiIcons();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 45aee5b..a658115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -30,6 +30,7 @@
import android.view.WindowInsets;
import androidx.annotation.VisibleForTesting;
+
import com.android.compose.animation.scene.ObservableTransitionState;
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.Dumpable;
@@ -69,7 +70,9 @@
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private boolean mIsStatusBarExpanded = false;
- private boolean mIsIdleOnGone = true;
+ // Whether the scene container has no UI to render, i.e. is in idle state on the Gone scene and
+ // without any overlays to display.
+ private boolean mIsSceneContainerUiEmpty = true;
private boolean mIsRemoteUserInteractionOngoing = false;
private boolean mShouldAdjustInsets = false;
private View mNotificationShadeWindowView;
@@ -134,7 +137,7 @@
if (SceneContainerFlag.isEnabled()) {
javaAdapter.alwaysCollectFlow(
sceneInteractor.get().getTransitionState(),
- this::onSceneChanged);
+ this::onSceneContainerTransition);
javaAdapter.alwaysCollectFlow(
sceneInteractor.get().isRemoteUserInteractionOngoing(),
this::onRemoteUserInteractionOngoingChanged);
@@ -172,11 +175,13 @@
}
}
- private void onSceneChanged(ObservableTransitionState transitionState) {
- boolean isIdleOnGone = transitionState.isIdle(Scenes.Gone);
- if (isIdleOnGone != mIsIdleOnGone) {
- mIsIdleOnGone = isIdleOnGone;
- if (!isIdleOnGone) {
+ private void onSceneContainerTransition(ObservableTransitionState transitionState) {
+ boolean isSceneContainerUiEmpty = transitionState.isIdle(Scenes.Gone)
+ && ((ObservableTransitionState.Idle) transitionState).getCurrentOverlays()
+ .isEmpty();
+ if (isSceneContainerUiEmpty != mIsSceneContainerUiEmpty) {
+ mIsSceneContainerUiEmpty = isSceneContainerUiEmpty;
+ if (!isSceneContainerUiEmpty) {
// make sure our state is sensible
mForceCollapsedUntilLayout = false;
}
@@ -296,7 +301,7 @@
// underneath.
return mIsStatusBarExpanded
|| (SceneContainerFlag.isEnabled()
- && (!mIsIdleOnGone || mIsRemoteUserInteractionOngoing))
+ && (!mIsSceneContainerUiEmpty || mIsRemoteUserInteractionOngoing))
|| mPrimaryBouncerInteractor.isShowing().getValue()
|| mAlternateBouncerInteractor.isVisibleState()
|| mUnlockedScreenOffAnimationController.isAnimationPlaying();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java
index 91ead61..fd16c60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/IconManager.java
@@ -20,7 +20,6 @@
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE_NEW;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI_NEW;
-import static com.android.systemui.statusbar.phone.ui.StatusBarIconControllerImpl.usesModeIcons;
import android.annotation.Nullable;
import android.content.Context;
@@ -31,6 +30,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIcon.Shape;
import com.android.systemui.demomode.DemoModeCommandReceiver;
+import com.android.systemui.modes.shared.ModesUiIcons;
import com.android.systemui.statusbar.BaseStatusBarFrameLayout;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusIconDisplayable;
@@ -233,7 +233,7 @@
}
protected LinearLayout.LayoutParams onCreateLayoutParams(Shape shape) {
- int width = usesModeIcons() && shape == StatusBarIcon.Shape.FIXED_SPACE
+ int width = ModesUiIcons.isEnabled() && shape == StatusBarIcon.Shape.FIXED_SPACE
? mIconSize
: ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -259,7 +259,7 @@
/** Called once an icon has been set. */
public void onSetIcon(int viewIndex, StatusBarIcon icon) {
StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex);
- if (usesModeIcons()) {
+ if (ModesUiIcons.isEnabled()) {
ViewGroup.LayoutParams current = view.getLayoutParams();
ViewGroup.LayoutParams desired = onCreateLayoutParams(icon.shape);
if (desired.width != current.width || desired.height != current.height) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
index 9b6d32b..e66e8138 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
@@ -42,6 +42,7 @@
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.modes.shared.ModesUiIcons;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarIconHolder;
@@ -242,10 +243,7 @@
public void setResourceIcon(String slot, @Nullable String resPackage,
@DrawableRes int iconResId, @Nullable Drawable preloadedIcon,
CharSequence contentDescription, StatusBarIcon.Shape shape) {
- if (!usesModeIcons()) {
- Log.wtf("TAG",
- "StatusBarIconController.setResourceIcon() should not be called without "
- + "MODES_UI & MODES_UI_ICONS!");
+ if (ModesUiIcons.isUnexpectedlyInLegacyMode()) {
// Fall back to old implementation, although it will not load the icon if it's from a
// different package.
setIcon(slot, iconResId, contentDescription);
@@ -580,9 +578,4 @@
return slot + EXTERNAL_SLOT_SUFFIX;
}
}
-
- static boolean usesModeIcons() {
- return android.app.Flags.modesApi() && android.app.Flags.modesUi()
- && android.app.Flags.modesUiIcons();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
index cf9f9f4..3cb7090 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PolicyModule.kt
@@ -21,6 +21,7 @@
import android.os.UserManager.DISALLOW_MICROPHONE_TOGGLE
import android.os.UserManager.DISALLOW_SHARE_LOCATION
import com.android.systemui.Flags
+import com.android.systemui.modes.shared.ModesUi
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.shared.model.TileCategory
@@ -142,7 +143,7 @@
dndTile: Provider<DndTile>,
modesTile: Provider<ModesTile>,
): QSTileImpl<*> {
- return if (android.app.Flags.modesUi()) modesTile.get() else dndTile.get()
+ return if (ModesUi.isEnabled) modesTile.get() else dndTile.get()
}
/** Inject flashlight config */
@@ -169,7 +170,7 @@
factory: QSTileViewModelFactory.Static<FlashlightTileModel>,
mapper: FlashlightMapper,
stateInteractor: FlashlightTileDataInteractor,
- userActionInteractor: FlashlightTileUserActionInteractor
+ userActionInteractor: FlashlightTileUserActionInteractor,
): QSTileViewModel =
factory.create(
TileSpec.create(FLASHLIGHT_TILE_SPEC),
@@ -206,7 +207,7 @@
factory: QSTileViewModelFactory.Static<LocationTileModel>,
mapper: LocationTileMapper,
stateInteractor: LocationTileDataInteractor,
- userActionInteractor: LocationTileUserActionInteractor
+ userActionInteractor: LocationTileUserActionInteractor,
): QSTileViewModel =
factory.create(
TileSpec.create(LOCATION_TILE_SPEC),
@@ -239,7 +240,7 @@
factory: QSTileViewModelFactory.Static<AlarmTileModel>,
mapper: AlarmTileMapper,
stateInteractor: AlarmTileDataInteractor,
- userActionInteractor: AlarmTileUserActionInteractor
+ userActionInteractor: AlarmTileUserActionInteractor,
): QSTileViewModel =
factory.create(
TileSpec.create(ALARM_TILE_SPEC),
@@ -272,7 +273,7 @@
factory: QSTileViewModelFactory.Static<UiModeNightTileModel>,
mapper: UiModeNightTileMapper,
stateInteractor: UiModeNightTileDataInteractor,
- userActionInteractor: UiModeNightTileUserActionInteractor
+ userActionInteractor: UiModeNightTileUserActionInteractor,
): QSTileViewModel =
factory.create(
TileSpec.create(UIMODENIGHT_TILE_SPEC),
@@ -306,7 +307,7 @@
factory: QSTileViewModelFactory.Static<WorkModeTileModel>,
mapper: WorkModeTileMapper,
stateInteractor: WorkModeTileDataInteractor,
- userActionInteractor: WorkModeTileUserActionInteractor
+ userActionInteractor: WorkModeTileUserActionInteractor,
): QSTileViewModel =
factory.create(
TileSpec.create(WORK_MODE_TILE_SPEC),
@@ -406,7 +407,7 @@
@IntoMap
@StringKey(DND_TILE_SPEC)
fun provideDndOrModesTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
- if (android.app.Flags.modesUi()) {
+ if (ModesUi.isEnabled) {
QSTileConfig(
tileSpec = TileSpec.create(DND_TILE_SPEC),
uiConfig =
@@ -438,9 +439,9 @@
factory: QSTileViewModelFactory.Static<ModesTileModel>,
mapper: ModesTileMapper,
stateInteractor: ModesTileDataInteractor,
- userActionInteractor: ModesTileUserActionInteractor
+ userActionInteractor: ModesTileUserActionInteractor,
): QSTileViewModel =
- if (android.app.Flags.modesUi() && Flags.qsNewTilesFuture())
+ if (ModesUi.isEnabled && Flags.qsNewTilesFuture())
factory.create(
TileSpec.create(DND_TILE_SPEC),
userActionInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
index af93880..27bc6d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTile.kt
@@ -59,32 +59,26 @@
)
CompositionLocalProvider(LocalContentColor provides contentColor) {
- Surface(
- color = tileColor,
- shape = RoundedCornerShape(16.dp),
- ) {
+ Surface(color = tileColor, shape = RoundedCornerShape(16.dp)) {
Row(
modifier =
Modifier.combinedClickable(
onClick = viewModel.onClick,
onLongClick = viewModel.onLongClick,
- onLongClickLabel = viewModel.onLongClickLabel
+ onLongClickLabel = viewModel.onLongClickLabel,
)
- .padding(20.dp)
+ .padding(16.dp)
.semantics { stateDescription = viewModel.stateDescription },
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement =
- Arrangement.spacedBy(
- space = 10.dp,
- alignment = Alignment.Start,
- ),
+ Arrangement.spacedBy(space = 8.dp, alignment = Alignment.Start),
) {
Icon(icon = viewModel.icon, modifier = Modifier.size(24.dp))
Column {
Text(
viewModel.text,
fontWeight = FontWeight.W500,
- modifier = Modifier.tileMarquee().testTag("name")
+ modifier = Modifier.tileMarquee().testTag("name"),
)
Text(
viewModel.subtext,
@@ -94,7 +88,7 @@
.testTag(if (viewModel.enabled) "stateOn" else "stateOff")
.clearAndSetSemantics {
contentDescription = viewModel.subtextDescription
- }
+ },
)
}
}
@@ -103,8 +97,5 @@
}
private fun Modifier.tileMarquee(): Modifier {
- return this.basicMarquee(
- iterations = 1,
- initialDelayMillis = 200,
- )
+ return this.basicMarquee(iterations = 1)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
index 73d361f6..5953ea5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
@@ -19,7 +19,6 @@
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
-import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.runtime.Composable
@@ -27,23 +26,20 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.systemui.Flags
import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModesDialogViewModel
@Composable
fun ModeTileGrid(viewModel: ModesDialogViewModel) {
val tiles by viewModel.tiles.collectAsStateWithLifecycle(initialValue = emptyList())
- // TODO(b/346519570): Handle what happens when we have more than a few modes.
LazyVerticalGrid(
- columns = GridCells.Fixed(2),
- modifier = Modifier.padding(8.dp).fillMaxWidth().heightIn(max = 300.dp),
+ columns = GridCells.Fixed(if (Flags.modesDialogSingleRows()) 1 else 2),
+ modifier = Modifier.fillMaxWidth().heightIn(max = 300.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
- items(
- tiles.size,
- key = { index -> tiles[index].id },
- ) { index ->
+ items(tiles.size, key = { index -> tiles[index].id }) { index ->
ModeTile(viewModel = tiles[index])
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index 5a77c04..6acc891 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -78,21 +78,21 @@
modifier = modifier
) {
TutorialButton(
- text = stringResource(R.string.touchpad_tutorial_back_gesture_button),
- onClick = onBackTutorialClicked,
+ text = stringResource(R.string.touchpad_tutorial_home_gesture_button),
+ onClick = onHomeTutorialClicked,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.weight(1f)
)
TutorialButton(
- text = stringResource(R.string.touchpad_tutorial_home_gesture_button),
- onClick = onHomeTutorialClicked,
- color = MaterialTheme.colorScheme.secondary,
+ text = stringResource(R.string.touchpad_tutorial_back_gesture_button),
+ onClick = onBackTutorialClicked,
+ color = MaterialTheme.colorScheme.tertiary,
modifier = Modifier.weight(1f)
)
TutorialButton(
text = stringResource(R.string.touchpad_tutorial_recent_apps_gesture_button),
onClick = onRecentAppsTutorialClicked,
- color = MaterialTheme.colorScheme.tertiary,
+ color = MaterialTheme.colorScheme.secondary,
modifier = Modifier.weight(1f)
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index 46ea352..6fe6547 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -29,12 +29,10 @@
import com.android.compose.theme.PlatformTheme
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.InputDeviceTutorialLogger.TutorialContext
-import com.android.systemui.inputdevice.tutorial.ui.composable.ActionKeyTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.RecentAppsGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.TutorialSelectionScreen
-import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.ACTION_KEY
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.BACK_GESTURE
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.HOME_GESTURE
import com.android.systemui.touchpad.tutorial.ui.viewmodel.Screen.RECENT_APPS_GESTURE
@@ -59,7 +57,6 @@
}
// required to handle 3+ fingers on touchpad
window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
- window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS)
}
private fun finishTutorial() {
@@ -104,10 +101,5 @@
onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
onBack = { vm.goTo(TUTORIAL_SELECTION) },
)
- ACTION_KEY -> // TODO(b/358105049) move action key tutorial to OOBE flow
- ActionKeyTutorialScreen(
- onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) },
- onBack = { vm.goTo(TUTORIAL_SELECTION) },
- )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
index 599e1b1..c56dcf3 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/TouchpadTutorialViewModel.kt
@@ -65,5 +65,4 @@
BACK_GESTURE,
HOME_GESTURE,
RECENT_APPS_GESTURE,
- ACTION_KEY,
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index db4f9ef..7166428 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -35,7 +35,6 @@
import static com.android.internal.jank.InteractionJankMonitor.CUJ_VOLUME_CONTROL;
import static com.android.internal.jank.InteractionJankMonitor.Configuration.Builder;
import static com.android.settingslib.flags.Flags.volumeDialogAudioSharingFix;
-import static com.android.systemui.Flags.hapticVolumeSlider;
import static com.android.systemui.volume.Events.DISMISS_REASON_POSTURE_CHANGED;
import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
@@ -928,10 +927,8 @@
}
private void addSliderHapticsToRow(VolumeRow row) {
- if (hapticVolumeSlider()) {
- row.createPlugin(mVibratorHelper, mSystemClock);
- HapticSliderViewBinder.bind(row.slider, row.mHapticPlugin);
- }
+ row.createPlugin(mVibratorHelper, mSystemClock);
+ HapticSliderViewBinder.bind(row.slider, row.mHapticPlugin);
}
@VisibleForTesting void addSliderHapticsToRows() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 52fde7e..e609d5f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -57,6 +57,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -494,7 +495,7 @@
@Test
public void testIgnoresSimStateCallback_rebroadcast() {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intent = defaultSimStateChangedIntent();
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(), intent);
mTestableLooper.processAllMessages();
@@ -515,7 +516,8 @@
@Test
public void testTelephonyCapable_SimState_Absent() {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+
+ Intent intent = defaultSimStateChangedIntent();
intent.putExtra(Intent.EXTRA_SIM_STATE,
Intent.SIM_STATE_ABSENT);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
@@ -526,7 +528,7 @@
@Test
public void testTelephonyCapable_SimState_CardIOError() {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intent = defaultSimStateChangedIntent();
intent.putExtra(Intent.EXTRA_SIM_STATE,
Intent.SIM_STATE_CARD_IO_ERROR);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(),
@@ -593,7 +595,7 @@
ServiceState state = new ServiceState();
state.setState(ServiceState.STATE_OUT_OF_SERVICE);
state.fillInNotifierBundle(data);
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intent = defaultSimStateChangedIntent();
intent.putExtra(Intent.EXTRA_SIM_STATE
, Intent.SIM_STATE_NOT_READY);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -608,7 +610,7 @@
ServiceState state = new ServiceState();
state.setState(ServiceState.STATE_OUT_OF_SERVICE);
state.fillInNotifierBundle(data);
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intent = defaultSimStateChangedIntent();
intent.putExtra(Intent.EXTRA_SIM_STATE
, Intent.SIM_STATE_READY);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -649,7 +651,7 @@
ServiceState state = new ServiceState();
state.setState(ServiceState.STATE_IN_SERVICE);
state.fillInNotifierBundle(data);
- Intent intentSimState = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ Intent intentSimState = defaultSimStateChangedIntent();
intentSimState.putExtra(Intent.EXTRA_SIM_STATE
, Intent.SIM_STATE_LOADED);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext()
@@ -1316,6 +1318,33 @@
}
@Test
+ public void testKeyguardMonitorStartsWhileUserIsSwitching() {
+ int userId = UserHandle.myUserId();
+ when(mUserTracker.getUserId()).thenReturn(userId);
+
+ /* First test the default behavior: handleUserSwitching() is not invoked */
+ when(mUserTracker.isUserSwitching()).thenReturn(false);
+ boolean invokeStartable = true;
+ mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext, invokeStartable);
+ mKeyguardUpdateMonitor.registerCallback(mTestCallback);
+ mTestableLooper.processAllMessages();
+
+ verify(mTestCallback, never()).onUserSwitching(userId);
+
+ reset(mTestCallback);
+
+ /* Next test user switching is already in progress when started */
+ when(mUserTracker.isUserSwitching()).thenReturn(true);
+ invokeStartable = false;
+ mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext, invokeStartable);
+ mKeyguardUpdateMonitor.registerCallback(mTestCallback);
+ mKeyguardUpdateMonitor.start();
+ mTestableLooper.processAllMessages();
+
+ verify(mTestCallback).onUserSwitching(userId);
+ }
+
+ @Test
public void testSecondaryLockscreenRequirement() {
when(mSelectedUserInteractor.getSelectedUserId()).thenReturn(UserHandle.myUserId());
when(mUserTracker.getUserId()).thenReturn(UserHandle.myUserId());
@@ -2256,6 +2285,12 @@
Assert.assertFalse(mKeyguardUpdateMonitor.forceIsDismissibleIsKeepingDeviceUnlocked());
}
+ private Intent defaultSimStateChangedIntent() {
+ Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0);
+ return intent;
+ }
+
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
@@ -2441,6 +2476,10 @@
AtomicInteger mCachedSimState = new AtomicInteger(-1);
protected TestableKeyguardUpdateMonitor(Context context) {
+ this(context, true);
+ }
+
+ protected TestableKeyguardUpdateMonitor(Context context, boolean invokeStart) {
super(context, mUserTracker,
TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(),
mBroadcastDispatcher, mDumpManager,
@@ -2461,7 +2500,9 @@
setAlternateBouncerVisibility(false);
setPrimaryBouncerVisibility(false);
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
- start();
+ if (invokeStart) {
+ start();
+ }
}
public boolean hasSimStateJustChanged() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java
index 530ae15..5e9f2a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/FullscreenMagnificationControllerTest.java
@@ -104,6 +104,7 @@
mContext = spy(mContext);
Display display = mock(Display.class);
when(display.getUniqueId()).thenReturn(UNIQUE_DISPLAY_ID_PRIMARY);
+ when(display.getType()).thenReturn(Display.TYPE_INTERNAL);
when(mContext.getDisplayNoVerify()).thenReturn(display);
// Override the resources to Display Primary
@@ -360,6 +361,7 @@
Display newDisplay = mock(Display.class);
when(newDisplay.getUniqueId()).thenReturn(UNIQUE_DISPLAY_ID_SECONDARY);
+ when(newDisplay.getType()).thenReturn(Display.TYPE_INTERNAL);
when(mContext.getDisplayNoVerify()).thenReturn(newDisplay);
// Override the resources to Display Secondary
mContext.getOrCreateTestableResources()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index c451c32..400b3b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -174,6 +174,7 @@
mMenuAnimationController = mMenuView.getMenuAnimationController();
doNothing().when(mSpyContext).startActivity(any());
+ doNothing().when(mSpyContext).startActivityAsUser(any(), any());
when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
mLastAccessibilityButtonTargets =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
index 9aaf295..a940bc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
@@ -8,7 +8,8 @@
import android.graphics.Point
import android.graphics.Rect
import android.os.Looper
-import android.platform.test.flag.junit.SetFlagsRule
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper.RunWithLooper
import android.view.IRemoteAnimationFinishedCallback
import android.view.RemoteAnimationAdapter
@@ -63,7 +64,6 @@
private lateinit var activityTransitionAnimator: ActivityTransitionAnimator
@get:Rule val rule = MockitoJUnit.rule()
- @get:Rule val setFlagsRule = SetFlagsRule()
@Before
fun setup() {
@@ -90,7 +90,7 @@
animator: ActivityTransitionAnimator = this.activityTransitionAnimator,
controller: ActivityTransitionAnimator.Controller? = this.controller,
animate: Boolean = true,
- intentStarter: (RemoteAnimationAdapter?) -> Int
+ intentStarter: (RemoteAnimationAdapter?) -> Int,
) {
// We start in a new thread so that we can ensure that the callbacks are called in the main
// thread.
@@ -98,7 +98,7 @@
animator.startIntentWithAnimation(
controller = controller,
animate = animate,
- intentStarter = intentStarter
+ intentStarter = intentStarter,
)
}
.join()
@@ -175,9 +175,9 @@
assertFalse(willAnimateCaptor.value)
}
+ @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY)
@Test
fun registersReturnIffCookieIsPresent() {
- setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY)
`when`(callback.isOnKeyguard()).thenReturn(false)
startIntentWithAnimation(activityTransitionAnimator, controller) { _ ->
@@ -203,10 +203,12 @@
assertTrue(testShellTransitions.remotesForTakeover.isEmpty())
}
+ @EnableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
@Test
fun registersLongLivedTransition() {
- setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY)
-
activityTransitionAnimator.register(
object : DelegateTransitionAnimatorController(controller) {
override val transitionCookie =
@@ -226,10 +228,12 @@
assertEquals(4, testShellTransitions.remotes.size)
}
+ @EnableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
@Test
fun registersLongLivedTransitionOverridingPreviousRegistration() {
- setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY)
-
val cookie = ActivityTransitionAnimator.TransitionCookie("test_cookie")
activityTransitionAnimator.register(
object : DelegateTransitionAnimatorController(controller) {
@@ -251,9 +255,9 @@
}
}
+ @DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED)
@Test
fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() {
- setFlagsRule.disableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY)
val controller =
object : DelegateTransitionAnimatorController(controller) {
@@ -266,9 +270,9 @@
}
}
+ @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED)
@Test
fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() {
- setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY)
// No TransitionCookie
val controllerWithoutCookie =
@@ -310,9 +314,12 @@
}
}
+ @EnableFlags(
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY,
+ Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED,
+ )
@Test
fun unregistersLongLivedTransition() {
- setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY)
val cookies = arrayOfNulls<ActivityTransitionAnimator.TransitionCookie>(3)
@@ -411,7 +418,7 @@
SurfaceControl(),
Rect(),
taskInfo,
- false
+ false,
)
}
}
@@ -430,7 +437,7 @@
override fun registerRemoteForTakeover(
filter: TransitionFilter,
- remoteTransition: RemoteTransition
+ remoteTransition: RemoteTransition,
) {
remotesForTakeover[filter] = remoteTransition
}
@@ -460,7 +467,7 @@
left = 300,
right = 400,
topCornerRadius = 10f,
- bottomCornerRadius = 20f
+ bottomCornerRadius = 20f,
)
private fun assertOnMainThread() {
@@ -480,7 +487,7 @@
override fun onTransitionAnimationProgress(
state: TransitionAnimator.State,
progress: Float,
- linearProgress: Float
+ linearProgress: Float,
) {
assertOnMainThread()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
index c65a117..d72b72c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
@@ -32,6 +32,7 @@
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.os.PersistableBundle;
+import android.os.UserHandle;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
@@ -101,8 +102,18 @@
when(mClipboardManager.getPrimaryClip()).thenReturn(mSampleClipData);
when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource);
- mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider,
- mClipboardToast, mClipboardManager, mKeyguardManager, mUiEventLogger);
+ mClipboardListener = new ClipboardListener(
+ getContext(),
+ mOverlayControllerProvider,
+ mClipboardToast,
+ user -> {
+ if (UserHandle.CURRENT.equals(user)) {
+ return mClipboardManager;
+ }
+ return null;
+ },
+ mKeyguardManager,
+ mUiEventLogger);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 597ffef..b0810a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -26,6 +26,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR;
+import static com.android.systemui.Flags.FLAG_SIM_PIN_BOUNCER_RESET;
import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
@@ -62,6 +63,7 @@
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -311,6 +313,28 @@
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void testHandleSystemReadyWhileUserIsSwitching() {
+ int userId = 1099;
+ when(mUserTracker.getUserId()).thenReturn(userId);
+
+ /* First test the default behavior: handleUserSwitching() is not invoked */
+ when(mUserTracker.isUserSwitching()).thenReturn(false);
+ mViewMediator.mUpdateCallback = mock(KeyguardUpdateMonitorCallback.class);
+ mViewMediator.onSystemReady();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(mViewMediator.mUpdateCallback, never()).onUserSwitching(userId);
+
+ /* Next test user switching is already in progress when started */
+ when(mUserTracker.isUserSwitching()).thenReturn(true);
+ mViewMediator.onSystemReady();
+ TestableLooper.get(this).processAllMessages();
+
+ verify(mViewMediator.mUpdateCallback).onUserSwitching(userId);
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
public void onLockdown_showKeyguard_evenIfKeyguardIsNotEnabledExternally() {
// GIVEN keyguard is not enabled and isn't showing
mViewMediator.onSystemReady();
@@ -588,6 +612,35 @@
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
+ @EnableFlags(FLAG_SIM_PIN_BOUNCER_RESET)
+ public void resetStateLocked_whenSimNotReadyAndWasLockedPrior() {
+ // When showing and provisioned
+ mViewMediator.onSystemReady();
+ when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+ mViewMediator.setShowingLocked(true, "");
+
+ // and a SIM becomes locked and requires a PIN
+ mViewMediator.mUpdateCallback.onSimStateChanged(
+ 1 /* subId */,
+ 0 /* slotId */,
+ TelephonyManager.SIM_STATE_PIN_REQUIRED);
+ TestableLooper.get(this).processAllMessages();
+
+ reset(mStatusBarKeyguardViewManager);
+
+ // but then disabled by a NOT_READY
+ mViewMediator.mUpdateCallback.onSimStateChanged(
+ 1 /* subId */,
+ 0 /* slotId */,
+ TelephonyManager.SIM_STATE_NOT_READY);
+ TestableLooper.get(this).processAllMessages();
+
+ // A call to reset the keyguard and bouncer was invoked
+ verify(mStatusBarKeyguardViewManager).reset(true);
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway_initiallyNotShowing() {
// When showing and provisioned
mViewMediator.onSystemReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
index 823a23d..d32d8cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
@@ -82,6 +82,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.After
@@ -200,7 +201,7 @@
Settings.Secure.getInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 1
+ 1,
)
private lateinit var staticMockSession: MockitoSession
@@ -221,9 +222,8 @@
Settings.Secure.putInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 1
+ 1,
)
-
mediaDataManager =
LegacyMediaDataManagerImpl(
context = context,
@@ -334,7 +334,7 @@
Settings.Secure.putInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- originalSmartspaceSetting
+ originalSmartspaceSetting,
)
}
@@ -365,7 +365,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
runCurrent()
@@ -378,7 +378,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
mediaDataManager.setInactive(PACKAGE_NAME, timedOut = true)
@@ -404,7 +404,7 @@
metadataBuilder
.putLong(
MediaConstants.METADATA_KEY_IS_EXPLICIT,
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT,
)
.build()
)
@@ -420,7 +420,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.isExplicit).isTrue()
}
@@ -438,7 +438,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.isExplicit).isFalse()
}
@@ -451,7 +451,7 @@
anyInt(),
eq(PACKAGE_NAME),
eq(mediaDataCaptor.value.instanceId),
- eq(MediaData.PLAYBACK_LOCAL)
+ eq(MediaData.PLAYBACK_LOCAL),
)
}
@@ -467,7 +467,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.active).isTrue()
}
@@ -483,7 +483,7 @@
anyInt(),
eq(SYSTEM_PACKAGE_NAME),
eq(mediaDataCaptor.value.instanceId),
- eq(MediaData.PLAYBACK_CAST_REMOTE)
+ eq(MediaData.PLAYBACK_CAST_REMOTE),
)
}
@@ -511,7 +511,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.app).isEqualTo(subName)
@@ -597,7 +597,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME)
assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle)
@@ -627,7 +627,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME)
assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle)
@@ -668,7 +668,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.song).isEqualTo(SESSION_TITLE)
}
@@ -683,7 +683,7 @@
mediaDataManager.onMediaDataLoaded(
KEY,
null,
- data.copy(song = SESSION_EMPTY_TITLE, resumeAction = Runnable {})
+ data.copy(song = SESSION_EMPTY_TITLE, resumeAction = Runnable {}),
)
// WHEN the notification is removed
@@ -698,7 +698,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
verify(logger, never())
.logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(instanceId))
@@ -716,7 +716,7 @@
mediaDataManager.onMediaDataLoaded(
KEY,
null,
- data.copy(song = SESSION_BLANK_TITLE, resumeAction = Runnable {})
+ data.copy(song = SESSION_BLANK_TITLE, resumeAction = Runnable {}),
)
// WHEN the notification is removed
@@ -731,7 +731,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
verify(logger, never())
.logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(instanceId))
@@ -756,7 +756,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
@@ -777,7 +777,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
@@ -789,7 +789,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
val data2 = mediaDataCaptor.value
assertThat(data2.resumption).isFalse()
@@ -807,7 +807,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener, never()).onMediaDataRemoved(eq(KEY), eq(false))
@@ -821,7 +821,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener).onMediaDataRemoved(eq(KEY_2), eq(false))
@@ -842,7 +842,7 @@
anyInt(),
eq(PACKAGE_NAME),
eq(mediaDataCaptor.value.instanceId),
- eq(MediaData.PLAYBACK_CAST_LOCAL)
+ eq(MediaData.PLAYBACK_CAST_LOCAL),
)
// WHEN the notification is removed
@@ -878,7 +878,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
}
@@ -932,7 +932,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
@@ -982,7 +982,7 @@
// WHEN resumption controls are added with explicit indicator
bundle.putLong(
MediaConstants.METADATA_KEY_IS_EXPLICIT,
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT,
)
val desc =
MediaDescription.Builder().run {
@@ -1015,7 +1015,7 @@
Bundle().apply {
putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
- MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
+ MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED,
)
putDouble(MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, progress)
}
@@ -1041,7 +1041,7 @@
Bundle().apply {
putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
- MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
+ MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED,
)
}
val desc =
@@ -1066,7 +1066,7 @@
Bundle().apply {
putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
- MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
+ MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED,
)
}
val desc =
@@ -1118,7 +1118,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
// Resumption controls are not added.
@@ -1130,7 +1130,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -1151,7 +1151,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
// Resumption controls are not added.
@@ -1163,7 +1163,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -1230,7 +1230,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -1256,7 +1256,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1280,7 +1280,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1312,7 +1312,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1359,7 +1359,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1393,7 +1393,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1424,7 +1424,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
verify(listener, never()).onSmartspaceMediaDataRemoved(eq(KEY_MEDIA_SMARTSPACE), eq(false))
}
@@ -1456,7 +1456,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1466,7 +1466,7 @@
Settings.Secure.putInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 0
+ 0,
)
tunableCaptor.value.onTuningChanged(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, "0")
@@ -1488,7 +1488,7 @@
Settings.Secure.putInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 0
+ 0,
)
tunableCaptor.value.onTuningChanged(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, "0")
@@ -1526,7 +1526,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.lastActive).isAtLeast(currentTime)
}
@@ -1553,7 +1553,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isAtLeast(currentTime)
@@ -1573,7 +1573,7 @@
mediaDataManager.onMediaDataLoaded(
KEY,
null,
- data.copy(resumeAction = Runnable {}, active = false)
+ data.copy(resumeAction = Runnable {}, active = false),
)
// WHEN the notification is removed
@@ -1589,7 +1589,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
@@ -1629,7 +1629,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.actionsToShowInCompact.size)
.isEqualTo(LegacyMediaDataManagerImpl.MAX_COMPACT_ACTIONS)
@@ -1664,7 +1664,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.actions.size)
.isEqualTo(LegacyMediaDataManagerImpl.MAX_NOTIFICATION_ACTIONS)
@@ -1695,7 +1695,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.semanticActions).isNull()
@@ -1868,7 +1868,7 @@
anyInt(),
eq(PACKAGE_NAME),
eq(instanceId),
- eq(MediaData.PLAYBACK_CAST_LOCAL)
+ eq(MediaData.PLAYBACK_CAST_LOCAL),
)
// update to remote cast
@@ -1879,7 +1879,7 @@
anyInt(),
eq(SYSTEM_PACKAGE_NAME),
eq(instanceId),
- eq(MediaData.PLAYBACK_CAST_REMOTE)
+ eq(MediaData.PLAYBACK_CAST_REMOTE),
)
}
@@ -1900,7 +1900,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.isPlaying).isTrue()
}
@@ -1948,7 +1948,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNotNull()
@@ -1977,7 +1977,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
runCurrent()
backgroundExecutor.runAllReady()
@@ -1992,7 +1992,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNotNull()
@@ -2017,7 +2017,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNull()
@@ -2074,7 +2074,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2082,7 +2082,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2141,7 +2141,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2149,7 +2149,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2193,7 +2193,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2201,7 +2201,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2245,7 +2245,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2253,7 +2253,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2279,7 +2279,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -2321,7 +2321,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2329,7 +2329,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2355,7 +2355,7 @@
any(),
any(),
anyInt(),
- anyInt()
+ anyInt(),
)
)
.thenReturn(1)
@@ -2385,7 +2385,7 @@
any(),
any(),
anyInt(),
- anyInt()
+ anyInt(),
)
)
.thenThrow(SecurityException("Test no permission"))
@@ -2421,7 +2421,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
verify(kosmos.mediaLogger).logDuplicateMediaNotification(eq(KEY))
}
@@ -2440,7 +2440,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY))
}
@@ -2448,6 +2448,7 @@
private fun TestScope.assertRunAllReady(foreground: Int = 0, background: Int = 0) {
runCurrent()
if (Flags.mediaLoadMetadataViaMediaDataLoader()) {
+ advanceUntilIdle()
// It doesn't make much sense to count tasks when we use coroutines in loader
// so this check is skipped in that scenario.
backgroundExecutor.runAllReady()
@@ -2478,7 +2479,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -2493,7 +2494,7 @@
/** Helper function to add a resumption control and capture the resulting MediaData */
private fun addResumeControlAndLoad(
desc: MediaDescription,
- packageName: String = PACKAGE_NAME
+ packageName: String = PACKAGE_NAME,
) {
mediaDataManager.addResumptionControls(
USER_ID,
@@ -2502,7 +2503,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- packageName
+ packageName,
)
testScope.assertRunAllReady(foreground = 1, background = 1)
@@ -2514,7 +2515,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
index 4cf7de3..90af932 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
@@ -90,6 +90,7 @@
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runCurrent
import org.junit.After
import org.junit.Before
@@ -212,7 +213,7 @@
Settings.Secure.getInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 1
+ 1,
)
private lateinit var staticMockSession: MockitoSession
@@ -233,7 +234,7 @@
Settings.Secure.putInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- 1
+ 1,
)
mediaDataProcessor =
MediaDataProcessor(
@@ -274,7 +275,7 @@
mediaDataCombineLatest = mediaDataCombineLatest,
mediaDataFilter = mediaDataFilter,
mediaFilterRepository = mediaFilterRepository,
- mediaFlags = kosmos.mediaFlags
+ mediaFlags = kosmos.mediaFlags,
)
mediaCarouselInteractor.start()
verify(mediaTimeoutListener).stateCallback = capture(stateCallbackCaptor)
@@ -356,7 +357,7 @@
Settings.Secure.putInt(
context.contentResolver,
Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
- originalSmartspaceSetting
+ originalSmartspaceSetting,
)
}
@@ -386,7 +387,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
testScope.runCurrent()
@@ -399,7 +400,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
mediaDataProcessor.setInactive(PACKAGE_NAME, timedOut = true)
@@ -425,7 +426,7 @@
metadataBuilder
.putLong(
MediaConstants.METADATA_KEY_IS_EXPLICIT,
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT,
)
.build()
)
@@ -440,7 +441,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.isExplicit).isTrue()
}
@@ -457,7 +458,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.isExplicit).isFalse()
}
@@ -470,7 +471,7 @@
anyInt(),
eq(PACKAGE_NAME),
eq(mediaDataCaptor.value.instanceId),
- eq(MediaData.PLAYBACK_LOCAL)
+ eq(MediaData.PLAYBACK_LOCAL),
)
}
@@ -485,7 +486,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.active).isTrue()
}
@@ -501,7 +502,7 @@
anyInt(),
eq(SYSTEM_PACKAGE_NAME),
eq(mediaDataCaptor.value.instanceId),
- eq(MediaData.PLAYBACK_CAST_REMOTE)
+ eq(MediaData.PLAYBACK_CAST_REMOTE),
)
}
@@ -529,7 +530,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.app).isEqualTo(subName)
@@ -615,7 +616,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME)
assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle)
@@ -645,7 +646,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME)
assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle)
@@ -686,7 +687,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.song).isEqualTo(SESSION_TITLE)
}
@@ -701,7 +702,7 @@
mediaDataProcessor.onMediaDataLoaded(
KEY,
null,
- data.copy(song = SESSION_EMPTY_TITLE, resumeAction = Runnable {})
+ data.copy(song = SESSION_EMPTY_TITLE, resumeAction = Runnable {}),
)
// WHEN the notification is removed
@@ -716,7 +717,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
verify(logger, never())
.logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(instanceId))
@@ -734,7 +735,7 @@
mediaDataProcessor.onMediaDataLoaded(
KEY,
null,
- data.copy(song = SESSION_BLANK_TITLE, resumeAction = Runnable {})
+ data.copy(song = SESSION_BLANK_TITLE, resumeAction = Runnable {}),
)
// WHEN the notification is removed
@@ -749,7 +750,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
verify(logger, never())
.logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(instanceId))
@@ -774,7 +775,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
@@ -795,7 +796,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
@@ -807,7 +808,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
val data2 = mediaDataCaptor.value
assertThat(data2.resumption).isFalse()
@@ -825,7 +826,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean())
@@ -839,7 +840,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener).onMediaDataRemoved(eq(KEY_2), eq(false))
@@ -860,7 +861,7 @@
anyInt(),
eq(PACKAGE_NAME),
eq(mediaDataCaptor.value.instanceId),
- eq(MediaData.PLAYBACK_CAST_LOCAL)
+ eq(MediaData.PLAYBACK_CAST_LOCAL),
)
// WHEN the notification is removed
@@ -896,7 +897,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
}
@@ -950,7 +951,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
@@ -1000,7 +1001,7 @@
// WHEN resumption controls are added with explicit indicator
bundle.putLong(
MediaConstants.METADATA_KEY_IS_EXPLICIT,
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT,
)
val desc =
MediaDescription.Builder().run {
@@ -1033,7 +1034,7 @@
Bundle().apply {
putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
- MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
+ MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED,
)
putDouble(MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, progress)
}
@@ -1059,7 +1060,7 @@
Bundle().apply {
putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
- MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
+ MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED,
)
}
val desc =
@@ -1084,7 +1085,7 @@
Bundle().apply {
putInt(
MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
- MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
+ MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED,
)
}
val desc =
@@ -1136,7 +1137,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
// Resumption controls are not added.
@@ -1148,7 +1149,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -1169,7 +1170,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
// Resumption controls are not added.
@@ -1181,7 +1182,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -1248,7 +1249,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -1274,7 +1275,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1298,7 +1299,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1330,7 +1331,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1377,7 +1378,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1411,7 +1412,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1442,7 +1443,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
verify(listener, never()).onSmartspaceMediaDataRemoved(eq(KEY_MEDIA_SMARTSPACE), eq(false))
}
@@ -1474,7 +1475,7 @@
expiryTimeMs = SMARTSPACE_EXPIRY_TIME,
)
),
- eq(false)
+ eq(false),
)
}
@@ -1536,7 +1537,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.lastActive).isAtLeast(currentTime)
}
@@ -1563,7 +1564,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isAtLeast(currentTime)
@@ -1583,7 +1584,7 @@
mediaDataProcessor.onMediaDataLoaded(
KEY,
null,
- data.copy(resumeAction = Runnable {}, active = false)
+ data.copy(resumeAction = Runnable {}, active = false),
)
// WHEN the notification is removed
@@ -1599,7 +1600,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
@@ -1639,7 +1640,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.actionsToShowInCompact.size)
.isEqualTo(MediaDataProcessor.MAX_COMPACT_ACTIONS)
@@ -1674,7 +1675,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.actions.size)
.isEqualTo(MediaDataProcessor.MAX_NOTIFICATION_ACTIONS)
@@ -1705,7 +1706,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value!!.semanticActions).isNull()
@@ -1944,7 +1945,7 @@
anyInt(),
eq(PACKAGE_NAME),
eq(instanceId),
- eq(MediaData.PLAYBACK_CAST_LOCAL)
+ eq(MediaData.PLAYBACK_CAST_LOCAL),
)
// update to remote cast
@@ -1955,7 +1956,7 @@
anyInt(),
eq(SYSTEM_PACKAGE_NAME),
eq(instanceId),
- eq(MediaData.PLAYBACK_CAST_REMOTE)
+ eq(MediaData.PLAYBACK_CAST_REMOTE),
)
}
@@ -1976,7 +1977,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.isPlaying).isTrue()
}
@@ -2024,7 +2025,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNotNull()
@@ -2052,7 +2053,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- PACKAGE_NAME
+ PACKAGE_NAME,
)
testScope.runCurrent()
backgroundExecutor.runAllReady()
@@ -2067,7 +2068,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNotNull()
@@ -2092,7 +2093,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNull()
@@ -2149,7 +2150,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2157,7 +2158,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2216,7 +2217,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2224,7 +2225,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2268,7 +2269,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2276,7 +2277,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2320,7 +2321,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2328,7 +2329,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2354,7 +2355,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -2396,7 +2397,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.active).isFalse()
@@ -2404,7 +2405,7 @@
.logActiveConvertedToResume(
anyInt(),
eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId)
+ eq(mediaDataCaptor.value.instanceId),
)
}
@@ -2430,7 +2431,7 @@
any(),
any(),
anyInt(),
- anyInt()
+ anyInt(),
)
)
.thenReturn(1)
@@ -2460,7 +2461,7 @@
any(),
any(),
anyInt(),
- anyInt()
+ anyInt(),
)
)
.thenThrow(SecurityException("Test no permission"))
@@ -2501,7 +2502,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
verify(kosmos.mediaLogger).logDuplicateMediaNotification(eq(KEY))
}
@@ -2525,7 +2526,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY))
}
@@ -2533,6 +2534,7 @@
private fun TestScope.assertRunAllReady(foreground: Int = 0, background: Int = 0) {
runCurrent()
if (Flags.mediaLoadMetadataViaMediaDataLoader()) {
+ advanceUntilIdle()
// It doesn't make much sense to count tasks when we use coroutines in loader
// so this check is skipped in that scenario.
backgroundExecutor.runAllReady()
@@ -2563,7 +2565,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
@@ -2578,7 +2580,7 @@
/** Helper function to add a resumption control and capture the resulting MediaData */
private fun addResumeControlAndLoad(
desc: MediaDescription,
- packageName: String = PACKAGE_NAME
+ packageName: String = PACKAGE_NAME,
) {
mediaDataProcessor.addResumptionControls(
USER_ID,
@@ -2587,7 +2589,7 @@
session.sessionToken,
APP_NAME,
pendingIntent,
- packageName
+ packageName,
)
testScope.assertRunAllReady(foreground = 1, background = 1)
@@ -2598,7 +2600,7 @@
capture(mediaDataCaptor),
eq(true),
eq(0),
- eq(false)
+ eq(false),
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
index 2370bca..0508c2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
@@ -25,6 +25,7 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardViewController
import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.ui.viewmodel.communalTransitionViewModel
@@ -34,6 +35,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.testScope
@@ -80,6 +82,8 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.atLeastOnce
+import org.mockito.kotlin.lastValue
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -118,6 +122,7 @@
private lateinit var mediaHierarchyManager: MediaHierarchyManager
private lateinit var isQsBypassingShade: MutableStateFlow<Boolean>
private lateinit var shadeExpansion: MutableStateFlow<Float>
+ private lateinit var anyShadeExpanded: MutableStateFlow<Boolean>
private lateinit var mediaFrame: ViewGroup
private val configurationController = FakeConfigurationController()
private val settings = FakeSettings()
@@ -137,8 +142,10 @@
whenever(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
isQsBypassingShade = MutableStateFlow(false)
shadeExpansion = MutableStateFlow(0f)
+ anyShadeExpanded = MutableStateFlow(false)
whenever(shadeInteractor.isQsBypassingShade).thenReturn(isQsBypassingShade)
whenever(shadeInteractor.shadeExpansion).thenReturn(shadeExpansion)
+ whenever(shadeInteractor.isAnyFullyExpanded).thenReturn(anyShadeExpanded)
mediaHierarchyManager =
MediaHierarchyManager(
context,
@@ -574,6 +581,72 @@
}
@Test
+ fun testCommunalLocationVisibilityWithShadeShowing() =
+ testScope.runTest {
+ whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ testScope = testScope,
+ )
+ kosmos.fakeCommunalSceneRepository.changeScene(CommunalScenes.Communal)
+ runCurrent()
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_COMMUNAL_HUB),
+ nullable(),
+ eq(false),
+ anyLong(),
+ anyLong()
+ )
+
+ val captor = ArgumentCaptor.forClass(Boolean::class.java)
+ verify(mediaCarouselScrollHandler, atLeastOnce()).visibleToUser = captor.capture()
+
+ assertThat(captor.lastValue).isTrue()
+
+ clearInvocations(mediaCarouselScrollHandler)
+ anyShadeExpanded.value = true
+ runCurrent()
+ verify(mediaCarouselScrollHandler, atLeastOnce()).visibleToUser = captor.capture()
+
+ assertThat(captor.lastValue).isFalse()
+ }
+
+ @Test
+ fun testCommunalLocationVisibilityWithPrimaryBouncerShowing() =
+ testScope.runTest {
+ whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true)
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GLANCEABLE_HUB,
+ testScope = testScope,
+ )
+ kosmos.fakeCommunalSceneRepository.changeScene(CommunalScenes.Communal)
+ runCurrent()
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_COMMUNAL_HUB),
+ nullable(),
+ eq(false),
+ anyLong(),
+ anyLong()
+ )
+
+ val captor = ArgumentCaptor.forClass(Boolean::class.java)
+ verify(mediaCarouselScrollHandler, atLeastOnce()).visibleToUser = captor.capture()
+
+ assertThat(captor.lastValue).isTrue()
+
+ clearInvocations(mediaCarouselScrollHandler)
+ kosmos.keyguardBouncerRepository.setPrimaryShow(true)
+ runCurrent()
+ verify(mediaCarouselScrollHandler, atLeastOnce()).visibleToUser = captor.capture()
+
+ assertThat(captor.lastValue).isFalse()
+ }
+
+ @Test
fun testCommunalLocation_showsOverLockscreen() =
testScope.runTest {
// Device is on lock screen.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 411ff91..8731853 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -77,7 +77,8 @@
private static final int TEST_CURRENT_VOLUME = 10;
// Mock
- private MediaOutputController mMediaOutputController = mock(MediaOutputController.class);
+ private MediaSwitchingController mMediaSwitchingController =
+ mock(MediaSwitchingController.class);
private MediaOutputDialog mMediaOutputDialog = mock(MediaOutputDialog.class);
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
private MediaDevice mMediaDevice2 = mock(MediaDevice.class);
@@ -95,13 +96,13 @@
@Before
public void setUp() {
- when(mMediaOutputController.getMediaItemList()).thenReturn(mMediaItems);
- when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false);
- when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(false);
- when(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).thenReturn(mIconCompat);
- when(mMediaOutputController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat);
- when(mMediaOutputController.getCurrentConnectedMediaDevice()).thenReturn(mMediaDevice1);
- when(mMediaOutputController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(true);
+ when(mMediaSwitchingController.getMediaItemList()).thenReturn(mMediaItems);
+ when(mMediaSwitchingController.hasAdjustVolumeUserRestriction()).thenReturn(false);
+ when(mMediaSwitchingController.isAnyDeviceTransferring()).thenReturn(false);
+ when(mMediaSwitchingController.getDeviceIconCompat(mMediaDevice1)).thenReturn(mIconCompat);
+ when(mMediaSwitchingController.getDeviceIconCompat(mMediaDevice2)).thenReturn(mIconCompat);
+ when(mMediaSwitchingController.getCurrentConnectedMediaDevice()).thenReturn(mMediaDevice1);
+ when(mMediaSwitchingController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(true);
when(mIconCompat.toIcon(mContext)).thenReturn(mIcon);
when(mMediaDevice1.getName()).thenReturn(TEST_DEVICE_NAME_1);
when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_ID_1);
@@ -116,7 +117,7 @@
mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice1));
mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice2));
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -142,7 +143,7 @@
@Test
public void onBindViewHolder_bindPairNew_verifyView() {
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -161,11 +162,13 @@
@Test
public void onBindViewHolder_bindGroup_withSessionName_verifyView() {
- when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(
- mMediaItems.stream().map((item) -> item.getMediaDevice().get()).collect(
- Collectors.toList()));
- when(mMediaOutputController.getSessionName()).thenReturn(TEST_SESSION_NAME);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ when(mMediaSwitchingController.getSelectedMediaDevice())
+ .thenReturn(
+ mMediaItems.stream()
+ .map((item) -> item.getMediaDevice().get())
+ .collect(Collectors.toList()));
+ when(mMediaSwitchingController.getSessionName()).thenReturn(TEST_SESSION_NAME);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -181,11 +184,13 @@
@Test
public void onBindViewHolder_bindGroup_noSessionName_verifyView() {
- when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(
- mMediaItems.stream().map((item) -> item.getMediaDevice().get()).collect(
- Collectors.toList()));
- when(mMediaOutputController.getSessionName()).thenReturn(null);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ when(mMediaSwitchingController.getSelectedMediaDevice())
+ .thenReturn(
+ mMediaItems.stream()
+ .map((item) -> item.getMediaDevice().get())
+ .collect(Collectors.toList()));
+ when(mMediaSwitchingController.getSessionName()).thenReturn(null);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -214,7 +219,7 @@
@Test
public void onBindViewHolder_bindNonRemoteConnectedDevice_verifyView() {
- when(mMediaOutputController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(false);
+ when(mMediaSwitchingController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(false);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -230,9 +235,9 @@
@Test
public void onBindViewHolder_bindConnectedRemoteDevice_verifyView() {
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
- ImmutableList.of(mMediaDevice2));
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ when(mMediaSwitchingController.getSelectableMediaDevice())
+ .thenReturn(ImmutableList.of(mMediaDevice2));
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -249,9 +254,9 @@
@Test
public void onBindViewHolder_bindConnectedRemoteDevice_verifyContentDescriptionNotNull() {
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
- ImmutableList.of(mMediaDevice2));
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ when(mMediaSwitchingController.getSelectableMediaDevice())
+ .thenReturn(ImmutableList.of(mMediaDevice2));
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -263,9 +268,8 @@
@Test
public void onBindViewHolder_bindSingleConnectedRemoteDevice_verifyView() {
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
- ImmutableList.of());
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(ImmutableList.of());
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -283,9 +287,8 @@
@Test
public void onBindViewHolder_bindConnectedRemoteDeviceWithOnGoingSession_verifyView() {
when(mMediaDevice1.hasOngoingSession()).thenReturn(true);
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
- ImmutableList.of());
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(ImmutableList.of());
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -305,9 +308,8 @@
public void onBindViewHolder_bindConnectedRemoteDeviceWithHostOnGoingSession_verifyView() {
when(mMediaDevice1.hasOngoingSession()).thenReturn(true);
when(mMediaDevice1.isHostForOngoingSession()).thenReturn(true);
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
- ImmutableList.of());
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(ImmutableList.of());
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -326,8 +328,8 @@
@Test
public void onBindViewHolder_bindConnectedDeviceWithMutingExpectedDeviceExist_verifyView() {
- when(mMediaOutputController.hasMutingExpectedDevice()).thenReturn(true);
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(false);
+ when(mMediaSwitchingController.hasMutingExpectedDevice()).thenReturn(true);
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(false);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
@@ -340,8 +342,8 @@
@Test
public void onBindViewHolder_isMutingExpectedDevice_verifyView() {
when(mMediaDevice1.isMutingExpectedDevice()).thenReturn(true);
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(false);
- when(mMediaOutputController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(false);
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(false);
+ when(mMediaSwitchingController.isActiveRemoteDevice(mMediaDevice1)).thenReturn(false);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -378,14 +380,14 @@
mOnSeekBarChangeListenerCaptor.getValue().onStopTrackingTouch(mViewHolder.mSeekBar);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
- verify(mMediaOutputController).logInteractionAdjustVolume(mMediaDevice1);
+ verify(mMediaSwitchingController).logInteractionAdjustVolume(mMediaDevice1);
}
@Test
public void onBindViewHolder_bindSelectableDevice_verifyView() {
List<MediaDevice> selectableDevices = new ArrayList<>();
selectableDevices.add(mMediaDevice2);
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(selectableDevices);
+ when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(selectableDevices);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
@@ -440,7 +442,7 @@
@Test
public void subStatusSupported_onBindViewHolder_bindHostDeviceWithOngoingSession_verifyView() {
- when(mMediaOutputController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(true);
+ when(mMediaSwitchingController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(true);
when(mMediaDevice1.isHostForOngoingSession()).thenReturn(true);
when(mMediaDevice1.hasSubtext()).thenReturn(true);
when(mMediaDevice1.getSubtext()).thenReturn(SUBTEXT_CUSTOM);
@@ -540,7 +542,7 @@
@Test
public void onBindViewHolder_inTransferring_bindTransferringDevice_verifyView() {
- when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(true);
+ when(mMediaSwitchingController.isAnyDeviceTransferring()).thenReturn(true);
when(mMediaDevice1.getState()).thenReturn(
LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -556,7 +558,7 @@
@Test
public void onBindViewHolder_bindGroupingDevice_verifyView() {
- when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(false);
+ when(mMediaSwitchingController.isAnyDeviceTransferring()).thenReturn(false);
when(mMediaDevice1.getState()).thenReturn(
LocalMediaManager.MediaDeviceState.STATE_GROUPING);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -572,7 +574,7 @@
@Test
public void onBindViewHolder_inTransferring_bindNonTransferringDevice_verifyView() {
- when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(true);
+ when(mMediaSwitchingController.isAnyDeviceTransferring()).thenReturn(true);
when(mMediaDevice2.getState()).thenReturn(
LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
@@ -586,7 +588,7 @@
@Test
public void onItemClick_clickPairNew_verifyLaunchBluetoothPairing() {
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -595,16 +597,16 @@
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
mViewHolder.mContainerLayout.performClick();
- verify(mMediaOutputController).launchBluetoothPairing(mViewHolder.mContainerLayout);
+ verify(mMediaSwitchingController).launchBluetoothPairing(mViewHolder.mContainerLayout);
}
@Test
public void onItemClick_clickDevice_verifyConnectDevice() {
- when(mMediaOutputController.isCurrentOutputDeviceHasSessionOngoing()).thenReturn(false);
+ when(mMediaSwitchingController.isCurrentOutputDeviceHasSessionOngoing()).thenReturn(false);
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_TRANSFER);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -613,16 +615,16 @@
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
mViewHolder.mContainerLayout.performClick();
- verify(mMediaOutputController).connectDevice(mMediaDevice2);
+ verify(mMediaSwitchingController).connectDevice(mMediaDevice2);
}
@Test
public void onItemClick_clickDeviceWithSessionOngoing_verifyShowsDialog() {
- when(mMediaOutputController.isCurrentOutputDeviceHasSessionOngoing()).thenReturn(true);
+ when(mMediaSwitchingController.isCurrentOutputDeviceHasSessionOngoing()).thenReturn(true);
assertThat(mMediaDevice2.getState()).isEqualTo(
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
when(mMediaDevice2.getSelectionBehavior()).thenReturn(SELECTION_BEHAVIOR_TRANSFER);
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
@@ -633,66 +635,68 @@
mMediaOutputAdapter.onBindViewHolder(spyMediaDeviceViewHolder, 1);
spyMediaDeviceViewHolder.mContainerLayout.performClick();
- verify(mMediaOutputController, never()).connectDevice(mMediaDevice2);
+ verify(mMediaSwitchingController, never()).connectDevice(mMediaDevice2);
verify(spyMediaDeviceViewHolder).showCustomEndSessionDialog(mMediaDevice2);
}
@Test
public void onItemClick_clicksWithMutingExpectedDeviceExist_cancelsMuteAwaitConnection() {
- when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(false);
- when(mMediaOutputController.hasMutingExpectedDevice()).thenReturn(true);
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(false);
+ when(mMediaSwitchingController.isAnyDeviceTransferring()).thenReturn(false);
+ when(mMediaSwitchingController.hasMutingExpectedDevice()).thenReturn(true);
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(false);
when(mMediaDevice1.isMutingExpectedDevice()).thenReturn(false);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
mViewHolder.mContainerLayout.performClick();
- verify(mMediaOutputController).cancelMuteAwaitConnection();
+ verify(mMediaSwitchingController).cancelMuteAwaitConnection();
}
@Test
public void onGroupActionTriggered_clicksEndAreaOfSelectableDevice_triggerGrouping() {
List<MediaDevice> selectableDevices = new ArrayList<>();
selectableDevices.add(mMediaDevice2);
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(selectableDevices);
+ when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(selectableDevices);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
mViewHolder.mEndTouchArea.performClick();
- verify(mMediaOutputController).addDeviceToPlayMedia(mMediaDevice2);
+ verify(mMediaSwitchingController).addDeviceToPlayMedia(mMediaDevice2);
}
@Test
public void onGroupActionTriggered_clickSelectedRemoteDevice_triggerUngrouping() {
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(
- ImmutableList.of(mMediaDevice2));
- when(mMediaOutputController.getDeselectableMediaDevice()).thenReturn(
- ImmutableList.of(mMediaDevice1));
- when(mMediaOutputController.isCurrentConnectedDeviceRemote()).thenReturn(true);
+ when(mMediaSwitchingController.getSelectableMediaDevice())
+ .thenReturn(ImmutableList.of(mMediaDevice2));
+ when(mMediaSwitchingController.getDeselectableMediaDevice())
+ .thenReturn(ImmutableList.of(mMediaDevice1));
+ when(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).thenReturn(true);
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
mViewHolder.mEndTouchArea.performClick();
- verify(mMediaOutputController).removeDeviceFromPlayMedia(mMediaDevice1);
+ verify(mMediaSwitchingController).removeDeviceFromPlayMedia(mMediaDevice1);
}
@Test
public void onItemClick_onGroupActionTriggered_verifySeekbarDisabled() {
- when(mMediaOutputController.getSelectedMediaDevice()).thenReturn(
- mMediaItems.stream().map((item) -> item.getMediaDevice().get()).collect(
- Collectors.toList()));
- mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
+ when(mMediaSwitchingController.getSelectedMediaDevice())
+ .thenReturn(
+ mMediaItems.stream()
+ .map((item) -> item.getMediaDevice().get())
+ .collect(Collectors.toList()));
+ mMediaOutputAdapter = new MediaOutputAdapter(mMediaSwitchingController);
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
List<MediaDevice> selectableDevices = new ArrayList<>();
selectableDevices.add(mMediaDevice1);
- when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(selectableDevices);
- when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(true);
+ when(mMediaSwitchingController.getSelectableMediaDevice()).thenReturn(selectableDevices);
+ when(mMediaSwitchingController.hasAdjustVolumeUserRestriction()).thenReturn(true);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
mViewHolder.mContainerLayout.performClick();
@@ -702,11 +706,11 @@
@Test
public void onBindViewHolder_volumeControlChangeToEnabled_enableSeekbarAgain() {
- when(mMediaOutputController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(false);
+ when(mMediaSwitchingController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(false);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mSeekBar.isEnabled()).isFalse();
- when(mMediaOutputController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(true);
+ when(mMediaSwitchingController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(true);
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mSeekBar.isEnabled()).isTrue();
@@ -719,7 +723,7 @@
mMediaOutputAdapter.updateColorScheme(wallpaperColors, true);
- verify(mMediaOutputController).setCurrentColorScheme(wallpaperColors, true);
+ verify(mMediaSwitchingController).setCurrentColorScheme(wallpaperColors, true);
}
@Test
@@ -727,7 +731,7 @@
mMediaOutputAdapter.updateItems();
List<MediaItem> updatedList = new ArrayList<>();
updatedList.add(MediaItem.createPairNewDeviceMediaItem());
- when(mMediaOutputController.getMediaItemList()).thenReturn(updatedList);
+ when(mMediaSwitchingController.getMediaItemList()).thenReturn(updatedList);
assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaItems.size());
mMediaOutputAdapter.updateItems();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index c8cc6b5..47371df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -104,7 +104,7 @@
private List<MediaController> mMediaControllers = new ArrayList<>();
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
- private MediaOutputController mMediaOutputController;
+ private MediaSwitchingController mMediaSwitchingController;
private int mHeaderIconRes;
private IconCompat mIconCompat;
private CharSequence mHeaderTitle;
@@ -132,8 +132,8 @@
VolumePanelGlobalStateInteractorKosmosKt.getVolumePanelGlobalStateInteractor(
mKosmos);
- mMediaOutputController =
- new MediaOutputController(
+ mMediaSwitchingController =
+ new MediaSwitchingController(
mContext,
TEST_PACKAGE,
mContext.getUser(),
@@ -153,12 +153,13 @@
// Using a fake package will cause routing operations to fail, so we intercept
// scanning-related operations.
- mMediaOutputController.mLocalMediaManager = mock(LocalMediaManager.class);
- doNothing().when(mMediaOutputController.mLocalMediaManager).startScan();
- doNothing().when(mMediaOutputController.mLocalMediaManager).stopScan();
+ mMediaSwitchingController.mLocalMediaManager = mock(LocalMediaManager.class);
+ doNothing().when(mMediaSwitchingController.mLocalMediaManager).startScan();
+ doNothing().when(mMediaSwitchingController.mLocalMediaManager).stopScan();
- mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mBroadcastSender,
- mMediaOutputController);
+ mMediaOutputBaseDialogImpl =
+ new MediaOutputBaseDialogImpl(
+ mContext, mBroadcastSender, mMediaSwitchingController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
}
@@ -176,7 +177,7 @@
public void refresh_withIconCompat_iconIsVisible() {
mIconCompat = IconCompat.createWithBitmap(
Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888));
- when(mMediaOutputBaseAdapter.getController()).thenReturn(mMediaOutputController);
+ when(mMediaOutputBaseAdapter.getController()).thenReturn(mMediaSwitchingController);
mMediaOutputBaseDialogImpl.refresh();
final ImageView view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
@@ -263,7 +264,7 @@
when(mMediaOutputBaseAdapter.isDragging()).thenReturn(true);
mMediaOutputBaseDialogImpl.refresh();
- assertThat(mMediaOutputController.isRefreshing()).isFalse();
+ assertThat(mMediaSwitchingController.isRefreshing()).isFalse();
}
@Test
@@ -335,12 +336,14 @@
class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
- MediaOutputBaseDialogImpl(Context context, BroadcastSender broadcastSender,
- MediaOutputController mediaOutputController) {
+ MediaOutputBaseDialogImpl(
+ Context context,
+ BroadcastSender broadcastSender,
+ MediaSwitchingController mediaSwitchingController) {
super(
context,
broadcastSender,
- mediaOutputController, /* includePlaybackAndAppMetadata */
+ mediaSwitchingController, /* includePlaybackAndAppMetadata */
true);
mAdapter = mMediaOutputBaseAdapter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
index 189a561..f0902e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogTest.java
@@ -119,7 +119,7 @@
private UserTracker mUserTracker = mock(UserTracker.class);
private MediaOutputBroadcastDialog mMediaOutputBroadcastDialog;
- private MediaOutputController mMediaOutputController;
+ private MediaSwitchingController mMediaSwitchingController;
@Before
public void setUp() {
@@ -133,8 +133,8 @@
VolumePanelGlobalStateInteractorKosmosKt.getVolumePanelGlobalStateInteractor(
mKosmos);
- mMediaOutputController =
- new MediaOutputController(
+ mMediaSwitchingController =
+ new MediaSwitchingController(
mContext,
TEST_PACKAGE,
mContext.getUser(),
@@ -151,9 +151,10 @@
mFlags,
volumePanelGlobalStateInteractor,
mUserTracker);
- mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
- mMediaOutputBroadcastDialog = new MediaOutputBroadcastDialog(mContext, false,
- mBroadcastSender, mMediaOutputController);
+ mMediaSwitchingController.mLocalMediaManager = mLocalMediaManager;
+ mMediaOutputBroadcastDialog =
+ new MediaOutputBroadcastDialog(
+ mContext, false, mBroadcastSender, mMediaSwitchingController);
mMediaOutputBroadcastDialog.show();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 90c2930..d3ecb3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -119,7 +119,7 @@
private List<MediaController> mMediaControllers = new ArrayList<>();
private MediaOutputDialog mMediaOutputDialog;
- private MediaOutputController mMediaOutputController;
+ private MediaSwitchingController mMediaSwitchingController;
private final List<String> mFeatures = new ArrayList<>();
@Override
@@ -146,8 +146,8 @@
VolumePanelGlobalStateInteractorKosmosKt.getVolumePanelGlobalStateInteractor(
mKosmos);
- mMediaOutputController =
- new MediaOutputController(
+ mMediaSwitchingController =
+ new MediaSwitchingController(
mContext,
TEST_PACKAGE,
mContext.getUser(),
@@ -164,8 +164,8 @@
mFlags,
volumePanelGlobalStateInteractor,
mUserTracker);
- mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
- mMediaOutputDialog = makeTestDialog(mMediaOutputController);
+ mMediaSwitchingController.mLocalMediaManager = mLocalMediaManager;
+ mMediaOutputDialog = makeTestDialog(mMediaSwitchingController);
mMediaOutputDialog.show();
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
@@ -388,12 +388,15 @@
public void getStopButtonText_notSupportsBroadcast_returnsDefaultText() {
String stopText = mContext.getText(
R.string.media_output_dialog_button_stop_casting).toString();
- MediaOutputController mockMediaOutputController = mock(MediaOutputController.class);
- when(mockMediaOutputController.isBroadcastSupported()).thenReturn(false);
+ MediaSwitchingController mockMediaSwitchingController =
+ mock(MediaSwitchingController.class);
+ when(mockMediaSwitchingController.isBroadcastSupported()).thenReturn(false);
- withTestDialog(mockMediaOutputController, testDialog -> {
- assertThat(testDialog.getStopButtonText().toString()).isEqualTo(stopText);
- });
+ withTestDialog(
+ mockMediaSwitchingController,
+ testDialog -> {
+ assertThat(testDialog.getStopButtonText().toString()).isEqualTo(stopText);
+ });
}
@Test
@@ -401,28 +404,35 @@
public void getStopButtonText_supportsBroadcast_returnsBroadcastText() {
String stopText = mContext.getText(R.string.media_output_broadcast).toString();
MediaDevice mMediaDevice = mock(MediaDevice.class);
- MediaOutputController mockMediaOutputController = mock(MediaOutputController.class);
- when(mockMediaOutputController.isBroadcastSupported()).thenReturn(true);
- when(mockMediaOutputController.getCurrentConnectedMediaDevice()).thenReturn(mMediaDevice);
- when(mockMediaOutputController.isBluetoothLeDevice(any())).thenReturn(true);
- when(mockMediaOutputController.isPlaying()).thenReturn(true);
- when(mockMediaOutputController.isBluetoothLeBroadcastEnabled()).thenReturn(false);
- withTestDialog(mockMediaOutputController, testDialog -> {
- assertThat(testDialog.getStopButtonText().toString()).isEqualTo(stopText);
- });
+ MediaSwitchingController mockMediaSwitchingController =
+ mock(MediaSwitchingController.class);
+ when(mockMediaSwitchingController.isBroadcastSupported()).thenReturn(true);
+ when(mockMediaSwitchingController.getCurrentConnectedMediaDevice())
+ .thenReturn(mMediaDevice);
+ when(mockMediaSwitchingController.isBluetoothLeDevice(any())).thenReturn(true);
+ when(mockMediaSwitchingController.isPlaying()).thenReturn(true);
+ when(mockMediaSwitchingController.isBluetoothLeBroadcastEnabled()).thenReturn(false);
+ withTestDialog(
+ mockMediaSwitchingController,
+ testDialog -> {
+ assertThat(testDialog.getStopButtonText().toString()).isEqualTo(stopText);
+ });
}
@Test
public void onStopButtonClick_notPlaying_releaseSession() {
- MediaOutputController mockMediaOutputController = mock(MediaOutputController.class);
- when(mockMediaOutputController.isBroadcastSupported()).thenReturn(false);
- when(mockMediaOutputController.getCurrentConnectedMediaDevice()).thenReturn(null);
- when(mockMediaOutputController.isPlaying()).thenReturn(false);
- withTestDialog(mockMediaOutputController, testDialog -> {
- testDialog.onStopButtonClick();
- });
+ MediaSwitchingController mockMediaSwitchingController =
+ mock(MediaSwitchingController.class);
+ when(mockMediaSwitchingController.isBroadcastSupported()).thenReturn(false);
+ when(mockMediaSwitchingController.getCurrentConnectedMediaDevice()).thenReturn(null);
+ when(mockMediaSwitchingController.isPlaying()).thenReturn(false);
+ withTestDialog(
+ mockMediaSwitchingController,
+ testDialog -> {
+ testDialog.onStopButtonClick();
+ });
- verify(mockMediaOutputController).releaseSession();
+ verify(mockMediaSwitchingController).releaseSession();
verify(mDialogTransitionAnimator).disableAllCurrentDialogsExitAnimations();
}
@@ -430,14 +440,14 @@
// Check the visibility metric logging by creating a new MediaOutput dialog,
// and verify if the calling times increases.
public void onCreate_ShouldLogVisibility() {
- withTestDialog(mMediaOutputController, testDialog -> {});
+ withTestDialog(mMediaSwitchingController, testDialog -> {});
verify(mUiEventLogger, times(2))
.log(MediaOutputDialog.MediaOutputEvent.MEDIA_OUTPUT_DIALOG_SHOW);
}
@NonNull
- private MediaOutputDialog makeTestDialog(MediaOutputController controller) {
+ private MediaOutputDialog makeTestDialog(MediaSwitchingController controller) {
return new MediaOutputDialog(
mContext,
false,
@@ -448,7 +458,8 @@
true);
}
- private void withTestDialog(MediaOutputController controller, Consumer<MediaOutputDialog> c) {
+ private void withTestDialog(
+ MediaSwitchingController controller, Consumer<MediaOutputDialog> c) {
MediaOutputDialog testDialog = makeTestDialog(controller);
testDialog.show();
c.accept(testDialog);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
similarity index 75%
rename from packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
index 714fad9..d3e20c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
@@ -43,6 +43,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.MediaDescription;
import android.media.MediaMetadata;
@@ -58,6 +59,7 @@
import android.os.PowerExemptionManager;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
import android.service.notification.StatusBarNotification;
import android.testing.TestableLooper;
import android.text.TextUtils;
@@ -67,8 +69,10 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.media.flags.Flags;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.media.InputMediaDevice;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.SysuiTestCase;
@@ -101,7 +105,7 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class MediaOutputControllerTest extends SysuiTestCase {
+public class MediaSwitchingControllerTest extends SysuiTestCase {
private static final String TEST_DEVICE_1_ID = "test_device_1_id";
private static final String TEST_DEVICE_2_ID = "test_device_2_id";
private static final String TEST_DEVICE_3_ID = "test_device_3_id";
@@ -126,8 +130,7 @@
private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
- @Mock
- private MediaOutputController.Callback mCb;
+ @Mock private MediaSwitchingController.Callback mCb;
@Mock
private MediaDevice mMediaDevice1;
@Mock
@@ -166,7 +169,8 @@
private FeatureFlags mFlags = mock(FeatureFlags.class);
private View mDialogLaunchView = mock(View.class);
- private MediaOutputController.Callback mCallback = mock(MediaOutputController.Callback.class);
+ private MediaSwitchingController.Callback mCallback =
+ mock(MediaSwitchingController.Callback.class);
final Notification mNotification = mock(Notification.class);
private final VolumePanelGlobalStateInteractor mVolumePanelGlobalStateInteractor =
@@ -175,7 +179,7 @@
private Context mSpyContext;
private String mPackageName = null;
- private MediaOutputController mMediaOutputController;
+ private MediaSwitchingController mMediaSwitchingController;
private LocalMediaManager mLocalMediaManager;
private List<MediaController> mMediaControllers = new ArrayList<>();
private List<MediaDevice> mMediaDevices = new ArrayList<>();
@@ -203,9 +207,8 @@
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(
mCachedBluetoothDeviceManager);
-
- mMediaOutputController =
- new MediaOutputController(
+ mMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
mPackageName,
mContext.getUser(),
@@ -222,9 +225,9 @@
mFlags,
mVolumePanelGlobalStateInteractor,
mUserTracker);
- mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
+ mLocalMediaManager = spy(mMediaSwitchingController.mLocalMediaManager);
when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(false);
- mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
+ mMediaSwitchingController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
builder.setTitle(TEST_SONG);
builder.setSubtitle(TEST_ARTIST);
@@ -264,26 +267,26 @@
@Test
public void start_verifyLocalMediaManagerInit() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
- verify(mLocalMediaManager).registerCallback(mMediaOutputController);
+ verify(mLocalMediaManager).registerCallback(mMediaSwitchingController);
verify(mLocalMediaManager).startScan();
}
@Test
public void stop_verifyLocalMediaManagerDeinit() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mLocalMediaManager);
- mMediaOutputController.stop();
+ mMediaSwitchingController.stop();
- verify(mLocalMediaManager).unregisterCallback(mMediaOutputController);
+ verify(mLocalMediaManager).unregisterCallback(mMediaSwitchingController);
verify(mLocalMediaManager).stopScan();
}
@Test
public void start_notificationNotFound_mediaControllerInitFromSession() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
verify(mSessionMediaController).registerCallback(any());
}
@@ -291,7 +294,7 @@
@Test
public void start_MediaNotificationFound_mediaControllerNotInitFromSession() {
when(mNotification.isMediaNotification()).thenReturn(true);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
verify(mSessionMediaController, never()).registerCallback(any());
verifyZeroInteractions(mMediaSessionManager);
@@ -299,8 +302,8 @@
@Test
public void start_withoutPackageName_verifyMediaControllerInit() {
- mMediaOutputController =
- new MediaOutputController(
+ mMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
null,
mContext.getUser(),
@@ -318,32 +321,32 @@
mVolumePanelGlobalStateInteractor,
mUserTracker);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
verify(mSessionMediaController, never()).registerCallback(any());
}
@Test
public void start_nearbyMediaDevicesManagerNotNull_registersNearbyDevicesCallback() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
verify(mNearbyMediaDevicesManager).registerNearbyDevicesCallback(any());
}
@Test
public void stop_withPackageName_verifyMediaControllerDeinit() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mSessionMediaController);
- mMediaOutputController.stop();
+ mMediaSwitchingController.stop();
verify(mSessionMediaController).unregisterCallback(any());
}
@Test
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
- mMediaOutputController =
- new MediaOutputController(
+ mMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
null,
mSpyContext.getUser(),
@@ -361,26 +364,26 @@
mVolumePanelGlobalStateInteractor,
mUserTracker);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
- mMediaOutputController.stop();
+ mMediaSwitchingController.stop();
verify(mSessionMediaController, never()).unregisterCallback(any());
}
@Test
public void stop_nearbyMediaDevicesManagerNotNull_unregistersNearbyDevicesCallback() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mSessionMediaController);
- mMediaOutputController.stop();
+ mMediaSwitchingController.stop();
verify(mNearbyMediaDevicesManager).unregisterNearbyDevicesCallback(any());
}
@Test
public void tryToLaunchMediaApplication_nullIntent_skip() {
- mMediaOutputController.tryToLaunchMediaApplication(mDialogLaunchView);
+ mMediaSwitchingController.tryToLaunchMediaApplication(mDialogLaunchView);
verify(mCb, never()).dismissDialog();
}
@@ -391,9 +394,9 @@
.thenReturn(mController);
Intent intent = new Intent(mPackageName);
doReturn(intent).when(mPackageManager).getLaunchIntentForPackage(mPackageName);
- mMediaOutputController.start(mCallback);
+ mMediaSwitchingController.start(mCallback);
- mMediaOutputController.tryToLaunchMediaApplication(mDialogLaunchView);
+ mMediaSwitchingController.tryToLaunchMediaApplication(mDialogLaunchView);
verify(mStarter).startActivity(any(Intent.class), anyBoolean(),
Mockito.eq(mController));
@@ -403,11 +406,12 @@
public void tryToLaunchInAppRoutingIntent_componentNameNotNull_startActivity() {
when(mDialogTransitionAnimator.createActivityTransitionController(any(View.class)))
.thenReturn(mController);
- mMediaOutputController.start(mCallback);
+ mMediaSwitchingController.start(mCallback);
when(mLocalMediaManager.getLinkedItemComponentName()).thenReturn(
new ComponentName(mPackageName, ""));
- mMediaOutputController.tryToLaunchInAppRoutingIntent(TEST_DEVICE_1_ID, mDialogLaunchView);
+ mMediaSwitchingController.tryToLaunchInAppRoutingIntent(
+ TEST_DEVICE_1_ID, mDialogLaunchView);
verify(mStarter).startActivity(any(Intent.class), anyBoolean(),
Mockito.eq(mController));
@@ -415,9 +419,9 @@
@Test
public void onDevicesUpdated_unregistersNearbyDevicesCallback() throws RemoteException {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
- mMediaOutputController.onDevicesUpdated(ImmutableList.of());
+ mMediaSwitchingController.onDevicesUpdated(ImmutableList.of());
verify(mNearbyMediaDevicesManager).unregisterNearbyDevicesCallback(any());
}
@@ -425,11 +429,11 @@
@Test
public void onDeviceListUpdate_withNearbyDevices_updatesRangeInformation()
throws RemoteException {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.onDevicesUpdated(mNearbyDevices);
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDevicesUpdated(mNearbyDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
verify(mMediaDevice1).setRangeZone(NearbyDevice.RANGE_FAR);
verify(mMediaDevice2).setRangeZone(NearbyDevice.RANGE_CLOSE);
@@ -438,11 +442,11 @@
@Test
public void onDeviceListUpdate_withNearbyDevices_rankByRangeInformation()
throws RemoteException {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.onDevicesUpdated(mNearbyDevices);
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDevicesUpdated(mNearbyDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
assertThat(mMediaDevices.get(0).getId()).isEqualTo(TEST_DEVICE_1_ID);
}
@@ -451,11 +455,11 @@
public void routeProcessSupport_onDeviceListUpdate_preferenceExist_NotUpdatesRangeInformation()
throws RemoteException {
when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(true);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.onDevicesUpdated(mNearbyDevices);
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDevicesUpdated(mNearbyDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
verify(mMediaDevice1, never()).setRangeZone(anyInt());
verify(mMediaDevice2, never()).setRangeZone(anyInt());
@@ -463,7 +467,8 @@
@Test
public void onDeviceListUpdate_verifyDeviceListCallback() {
- // This test relies on mMediaOutputController.start being called while the selected device
+ // This test relies on mMediaSwitchingController.start being called while the selected
+ // device
// list has exactly one item, and that item's id is:
// - Different from both ids in mMediaDevices.
// - Different from the id of the route published by the device under test (usually the
@@ -475,12 +480,12 @@
.when(mLocalMediaManager)
.getSelectedMediaDevice();
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
final List<MediaDevice> devices = new ArrayList<>();
- for (MediaItem item : mMediaOutputController.getMediaItemList()) {
+ for (MediaItem item : mMediaSwitchingController.getMediaItemList()) {
if (item.getMediaDevice().isPresent()) {
devices.add(item.getMediaDevice().get());
}
@@ -488,14 +493,15 @@
assertThat(devices.containsAll(mMediaDevices)).isTrue();
assertThat(devices.size()).isEqualTo(mMediaDevices.size());
- assertThat(mMediaOutputController.getMediaItemList().size()).isEqualTo(
- mMediaDevices.size() + 2);
+ assertThat(mMediaSwitchingController.getMediaItemList().size())
+ .isEqualTo(mMediaDevices.size() + 2);
verify(mCb).onDeviceListChanged();
}
@Test
public void advanced_onDeviceListUpdateWithConnectedDeviceRemote_verifyItemSize() {
- // This test relies on mMediaOutputController.start being called while the selected device
+ // This test relies on mMediaSwitchingController.start being called while the selected
+ // device
// list has exactly one item, and that item's id is:
// - Different from both ids in mMediaDevices.
// - Different from the id of the route published by the device under test (usually the
@@ -510,12 +516,12 @@
when(mMediaDevice1.getFeatures()).thenReturn(
ImmutableList.of(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK));
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice1);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
final List<MediaDevice> devices = new ArrayList<>();
- for (MediaItem item : mMediaOutputController.getMediaItemList()) {
+ for (MediaItem item : mMediaSwitchingController.getMediaItemList()) {
if (item.getMediaDevice().isPresent()) {
devices.add(item.getMediaDevice().get());
}
@@ -523,23 +529,72 @@
assertThat(devices.containsAll(mMediaDevices)).isTrue();
assertThat(devices.size()).isEqualTo(mMediaDevices.size());
- assertThat(mMediaOutputController.getMediaItemList().size()).isEqualTo(
- mMediaDevices.size() + 1);
+ assertThat(mMediaSwitchingController.getMediaItemList().size())
+ .isEqualTo(mMediaDevices.size() + 1);
verify(mCb).onDeviceListChanged();
}
+ @EnableFlags(Flags.FLAG_ENABLE_AUDIO_INPUT_DEVICE_ROUTING_AND_VOLUME_CONTROL)
+ @Test
+ public void onInputDeviceListUpdate_verifyDeviceListCallback() {
+ AudioDeviceInfo[] audioDeviceInfos = {};
+ when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
+ .thenReturn(audioDeviceInfos);
+ mMediaSwitchingController.start(mCb);
+
+ // Output devices have changed.
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
+
+ final int MAX_VOLUME = 1;
+ final int CURRENT_VOLUME = 0;
+ final boolean IS_VOLUME_FIXED = true;
+ final MediaDevice mediaDevice3 =
+ InputMediaDevice.create(
+ mContext,
+ TEST_DEVICE_3_ID,
+ AudioDeviceInfo.TYPE_BUILTIN_MIC,
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ IS_VOLUME_FIXED);
+ final MediaDevice mediaDevice4 =
+ InputMediaDevice.create(
+ mContext,
+ TEST_DEVICE_4_ID,
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
+ MAX_VOLUME,
+ CURRENT_VOLUME,
+ IS_VOLUME_FIXED);
+ final List<MediaDevice> inputDevices = new ArrayList<>();
+ inputDevices.add(mediaDevice3);
+ inputDevices.add(mediaDevice4);
+
+ // Input devices have changed.
+ mMediaSwitchingController.mInputDeviceCallback.onInputDeviceListUpdated(inputDevices);
+
+ final List<MediaDevice> devices = new ArrayList<>();
+ for (MediaItem item : mMediaSwitchingController.getMediaItemList()) {
+ if (item.getMediaDevice().isPresent()) {
+ devices.add(item.getMediaDevice().get());
+ }
+ }
+
+ assertThat(devices).containsAtLeastElementsIn(mMediaDevices);
+ assertThat(devices).hasSize(mMediaDevices.size() + inputDevices.size());
+ verify(mCb, atLeastOnce()).onDeviceListChanged();
+ }
+
@Test
public void advanced_categorizeMediaItems_withSuggestedDevice_verifyDeviceListSize() {
when(mMediaDevice1.isSuggestedDevice()).thenReturn(true);
when(mMediaDevice2.isSuggestedDevice()).thenReturn(false);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.getMediaItemList().clear();
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.getMediaItemList().clear();
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
final List<MediaDevice> devices = new ArrayList<>();
int dividerSize = 0;
- for (MediaItem item : mMediaOutputController.getMediaItemList()) {
+ for (MediaItem item : mMediaSwitchingController.getMediaItemList()) {
if (item.getMediaDevice().isPresent()) {
devices.add(item.getMediaDevice().get());
}
@@ -556,33 +611,33 @@
@Test
public void onDeviceListUpdate_isRefreshing_updatesNeedRefreshToTrue() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.mIsRefreshing = true;
+ mMediaSwitchingController.mIsRefreshing = true;
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
- assertThat(mMediaOutputController.mNeedRefresh).isTrue();
+ assertThat(mMediaSwitchingController.mNeedRefresh).isTrue();
}
@Test
public void advanced_onDeviceListUpdate_isRefreshing_updatesNeedRefreshToTrue() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.mIsRefreshing = true;
+ mMediaSwitchingController.mIsRefreshing = true;
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
- assertThat(mMediaOutputController.mNeedRefresh).isTrue();
+ assertThat(mMediaSwitchingController.mNeedRefresh).isTrue();
}
@Test
public void cancelMuteAwaitConnection_cancelsWithMediaManager() {
when(mAudioManager.getMutingExpectedDevice()).thenReturn(mock(AudioDeviceAttributes.class));
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.cancelMuteAwaitConnection();
+ mMediaSwitchingController.cancelMuteAwaitConnection();
verify(mAudioManager).cancelMuteAwaitConnection(any());
}
@@ -590,17 +645,17 @@
@Test
public void cancelMuteAwaitConnection_audioManagerIsNull_noAction() {
when(mAudioManager.getMutingExpectedDevice()).thenReturn(null);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.cancelMuteAwaitConnection();
+ mMediaSwitchingController.cancelMuteAwaitConnection();
verify(mAudioManager, never()).cancelMuteAwaitConnection(any());
}
@Test
public void getAppSourceName_packageNameIsNull_returnsNull() {
- MediaOutputController testMediaOutputController =
- new MediaOutputController(
+ MediaSwitchingController testMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
"",
mSpyContext.getUser(),
@@ -617,25 +672,25 @@
mFlags,
mVolumePanelGlobalStateInteractor,
mUserTracker);
- testMediaOutputController.start(mCb);
+ testMediaSwitchingController.start(mCb);
reset(mCb);
- testMediaOutputController.getAppSourceName();
+ testMediaSwitchingController.getAppSourceName();
- assertThat(testMediaOutputController.getAppSourceName()).isNull();
+ assertThat(testMediaSwitchingController.getAppSourceName()).isNull();
}
@Test
public void isActiveItem_deviceNotConnected_returnsFalse() {
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
- assertThat(mMediaOutputController.isActiveItem(mMediaDevice1)).isFalse();
+ assertThat(mMediaSwitchingController.isActiveItem(mMediaDevice1)).isFalse();
}
@Test
public void getNotificationSmallIcon_packageNameIsNull_returnsNull() {
- MediaOutputController testMediaOutputController =
- new MediaOutputController(
+ MediaSwitchingController testMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
"",
mSpyContext.getUser(),
@@ -652,23 +707,23 @@
mFlags,
mVolumePanelGlobalStateInteractor,
mUserTracker);
- testMediaOutputController.start(mCb);
+ testMediaSwitchingController.start(mCb);
reset(mCb);
- testMediaOutputController.getAppSourceName();
+ testMediaSwitchingController.getAppSourceName();
- assertThat(testMediaOutputController.getNotificationSmallIcon()).isNull();
+ assertThat(testMediaSwitchingController.getNotificationSmallIcon()).isNull();
}
@Test
public void refreshDataSetIfNeeded_needRefreshIsTrue_setsToFalse() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.mNeedRefresh = true;
+ mMediaSwitchingController.mNeedRefresh = true;
- mMediaOutputController.refreshDataSetIfNeeded();
+ mMediaSwitchingController.refreshDataSetIfNeeded();
- assertThat(mMediaOutputController.mNeedRefresh).isFalse();
+ assertThat(mMediaSwitchingController.mNeedRefresh).isFalse();
}
@Test
@@ -677,13 +732,13 @@
ImmutableList.of(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK));
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice1);
- assertThat(mMediaOutputController.isCurrentConnectedDeviceRemote()).isTrue();
+ assertThat(mMediaSwitchingController.isCurrentConnectedDeviceRemote()).isTrue();
}
@Test
public void addDeviceToPlayMedia_callsLocalMediaManager() {
- MediaOutputController testMediaOutputController =
- new MediaOutputController(
+ MediaSwitchingController testMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
null,
mSpyContext.getUser(),
@@ -702,16 +757,16 @@
mUserTracker);
LocalMediaManager mockLocalMediaManager = mock(LocalMediaManager.class);
- testMediaOutputController.mLocalMediaManager = mockLocalMediaManager;
+ testMediaSwitchingController.mLocalMediaManager = mockLocalMediaManager;
- testMediaOutputController.addDeviceToPlayMedia(mMediaDevice2);
+ testMediaSwitchingController.addDeviceToPlayMedia(mMediaDevice2);
verify(mockLocalMediaManager).addDeviceToPlayMedia(mMediaDevice2);
}
@Test
public void removeDeviceFromPlayMedia_callsLocalMediaManager() {
- MediaOutputController testMediaOutputController =
- new MediaOutputController(
+ MediaSwitchingController testMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
null,
mSpyContext.getUser(),
@@ -730,15 +785,15 @@
mUserTracker);
LocalMediaManager mockLocalMediaManager = mock(LocalMediaManager.class);
- testMediaOutputController.mLocalMediaManager = mockLocalMediaManager;
+ testMediaSwitchingController.mLocalMediaManager = mockLocalMediaManager;
- testMediaOutputController.removeDeviceFromPlayMedia(mMediaDevice2);
+ testMediaSwitchingController.removeDeviceFromPlayMedia(mMediaDevice2);
verify(mockLocalMediaManager).removeDeviceFromPlayMedia(mMediaDevice2);
}
@Test
public void getDeselectableMediaDevice_triggersFromLocalMediaManager() {
- mMediaOutputController.getDeselectableMediaDevice();
+ mMediaSwitchingController.getDeselectableMediaDevice();
verify(mLocalMediaManager).getDeselectableMediaDevice();
}
@@ -746,108 +801,108 @@
@Test
public void adjustSessionVolume_adjustWithoutId_triggersFromLocalMediaManager() {
int testVolume = 10;
- mMediaOutputController.adjustSessionVolume(testVolume);
+ mMediaSwitchingController.adjustSessionVolume(testVolume);
verify(mLocalMediaManager).adjustSessionVolume(testVolume);
}
@Test
public void logInteractionAdjustVolume_triggersFromMetricLogger() {
- MediaOutputMetricLogger spyMediaOutputMetricLogger = spy(
- mMediaOutputController.mMetricLogger);
- mMediaOutputController.mMetricLogger = spyMediaOutputMetricLogger;
+ MediaOutputMetricLogger spyMediaOutputMetricLogger =
+ spy(mMediaSwitchingController.mMetricLogger);
+ mMediaSwitchingController.mMetricLogger = spyMediaOutputMetricLogger;
- mMediaOutputController.logInteractionAdjustVolume(mMediaDevice1);
+ mMediaSwitchingController.logInteractionAdjustVolume(mMediaDevice1);
verify(spyMediaOutputMetricLogger).logInteractionAdjustVolume(mMediaDevice1);
}
@Test
public void getSessionVolumeMax_triggersFromLocalMediaManager() {
- mMediaOutputController.getSessionVolumeMax();
+ mMediaSwitchingController.getSessionVolumeMax();
verify(mLocalMediaManager).getSessionVolumeMax();
}
@Test
public void getSessionVolume_triggersFromLocalMediaManager() {
- mMediaOutputController.getSessionVolume();
+ mMediaSwitchingController.getSessionVolume();
verify(mLocalMediaManager).getSessionVolume();
}
@Test
public void getSessionName_triggersFromLocalMediaManager() {
- mMediaOutputController.getSessionName();
+ mMediaSwitchingController.getSessionName();
verify(mLocalMediaManager).getSessionName();
}
@Test
public void releaseSession_triggersFromLocalMediaManager() {
- mMediaOutputController.releaseSession();
+ mMediaSwitchingController.releaseSession();
verify(mLocalMediaManager).releaseSession();
}
@Test
public void isAnyDeviceTransferring_noDevicesStateIsConnecting_returnsFalse() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
- assertThat(mMediaOutputController.isAnyDeviceTransferring()).isFalse();
+ assertThat(mMediaSwitchingController.isAnyDeviceTransferring()).isFalse();
}
@Test
public void isAnyDeviceTransferring_deviceStateIsConnecting_returnsTrue() {
when(mMediaDevice1.getState()).thenReturn(
LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
- assertThat(mMediaOutputController.isAnyDeviceTransferring()).isTrue();
+ assertThat(mMediaSwitchingController.isAnyDeviceTransferring()).isTrue();
}
@Test
public void isAnyDeviceTransferring_advancedLayoutSupport() {
when(mMediaDevice1.getState()).thenReturn(
LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
- mMediaOutputController.start(mCb);
- mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+ mMediaSwitchingController.start(mCb);
+ mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
- assertThat(mMediaOutputController.isAnyDeviceTransferring()).isTrue();
+ assertThat(mMediaSwitchingController.isAnyDeviceTransferring()).isTrue();
}
@Test
public void isPlaying_stateIsNull() {
when(mSessionMediaController.getPlaybackState()).thenReturn(null);
- assertThat(mMediaOutputController.isPlaying()).isFalse();
+ assertThat(mMediaSwitchingController.isPlaying()).isFalse();
}
@Test
public void onSelectedDeviceStateChanged_verifyCallback() {
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.connectDevice(mMediaDevice1);
+ mMediaSwitchingController.connectDevice(mMediaDevice1);
- mMediaOutputController.onSelectedDeviceStateChanged(mMediaDevice1,
- LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
+ mMediaSwitchingController.onSelectedDeviceStateChanged(
+ mMediaDevice1, LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
verify(mCb).onRouteChanged();
}
@Test
public void onDeviceAttributesChanged_verifyCallback() {
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.onDeviceAttributesChanged();
+ mMediaSwitchingController.onDeviceAttributesChanged();
verify(mCb).onRouteChanged();
}
@@ -855,11 +910,11 @@
@Test
public void onRequestFailed_verifyCallback() {
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice1);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
reset(mCb);
- mMediaOutputController.connectDevice(mMediaDevice2);
+ mMediaSwitchingController.connectDevice(mMediaDevice2);
- mMediaOutputController.onRequestFailed(0 /* reason */);
+ mMediaSwitchingController.onRequestFailed(0 /* reason */);
verify(mCb, atLeastOnce()).onRouteChanged();
}
@@ -868,37 +923,40 @@
public void getHeaderTitle_withoutMetadata_returnDefaultString() {
when(mSessionMediaController.getMetadata()).thenReturn(null);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
- assertThat(mMediaOutputController.getHeaderTitle()).isEqualTo(
- mContext.getText(R.string.controls_media_title));
+ assertThat(
+ mMediaSwitchingController
+ .getHeaderTitle()
+ .equals(mContext.getText(R.string.controls_media_title)))
+ .isTrue();
}
@Test
public void getHeaderTitle_withMetadata_returnSongName() {
when(mSessionMediaController.getMetadata()).thenReturn(mMediaMetadata);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
- assertThat(mMediaOutputController.getHeaderTitle()).isEqualTo(TEST_SONG);
+ assertThat(mMediaSwitchingController.getHeaderTitle().equals(TEST_SONG)).isTrue();
}
@Test
public void getHeaderSubTitle_withoutMetadata_returnNull() {
when(mSessionMediaController.getMetadata()).thenReturn(null);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
- assertThat(mMediaOutputController.getHeaderSubTitle()).isNull();
+ assertThat(mMediaSwitchingController.getHeaderSubTitle()).isNull();
}
@Test
public void getHeaderSubTitle_withMetadata_returnArtistName() {
when(mSessionMediaController.getMetadata()).thenReturn(mMediaMetadata);
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.start(mCb);
- assertThat(mMediaOutputController.getHeaderSubTitle()).isEqualTo(TEST_ARTIST);
+ assertThat(mMediaSwitchingController.getHeaderSubTitle().equals(TEST_ARTIST)).isTrue();
}
@Test
@@ -911,8 +969,8 @@
mRoutingSessionInfos.add(mRemoteSessionInfo);
when(mLocalMediaManager.getRemoteRoutingSessions()).thenReturn(mRoutingSessionInfos);
- assertThat(mMediaOutputController.getActiveRemoteMediaDevices()).containsExactly(
- mRemoteSessionInfo);
+ assertThat(mMediaSwitchingController.getActiveRemoteMediaDevices())
+ .containsExactly(mRemoteSessionInfo);
}
@Test
@@ -933,7 +991,8 @@
selectableMediaDevices.add(selectableMediaDevice2);
doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice();
doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice();
- final List<MediaDevice> groupMediaDevices = mMediaOutputController.getGroupMediaDevices();
+ final List<MediaDevice> groupMediaDevices =
+ mMediaSwitchingController.getGroupMediaDevices();
// Reset order
selectedMediaDevices.clear();
selectedMediaDevices.add(selectedMediaDevice2);
@@ -941,7 +1000,7 @@
selectableMediaDevices.clear();
selectableMediaDevices.add(selectableMediaDevice2);
selectableMediaDevices.add(selectableMediaDevice1);
- final List<MediaDevice> newDevices = mMediaOutputController.getGroupMediaDevices();
+ final List<MediaDevice> newDevices = mMediaSwitchingController.getGroupMediaDevices();
assertThat(newDevices.size()).isEqualTo(groupMediaDevices.size());
for (int i = 0; i < groupMediaDevices.size(); i++) {
@@ -970,7 +1029,8 @@
selectableMediaDevices.add(selectableMediaDevice2);
doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice();
doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice();
- final List<MediaDevice> groupMediaDevices = mMediaOutputController.getGroupMediaDevices();
+ final List<MediaDevice> groupMediaDevices =
+ mMediaSwitchingController.getGroupMediaDevices();
// Reset order
selectedMediaDevices.clear();
selectedMediaDevices.add(selectedMediaDevice2);
@@ -979,7 +1039,7 @@
selectableMediaDevices.add(selectableMediaDevice3);
selectableMediaDevices.add(selectableMediaDevice2);
selectableMediaDevices.add(selectableMediaDevice1);
- final List<MediaDevice> newDevices = mMediaOutputController.getGroupMediaDevices();
+ final List<MediaDevice> newDevices = mMediaSwitchingController.getGroupMediaDevices();
assertThat(newDevices.size()).isEqualTo(5);
for (int i = 0; i < groupMediaDevices.size(); i++) {
@@ -991,8 +1051,8 @@
@Test
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
- mMediaOutputController =
- new MediaOutputController(
+ mMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
null,
mSpyContext.getUser(),
@@ -1010,7 +1070,7 @@
mVolumePanelGlobalStateInteractor,
mUserTracker);
- assertThat(mMediaOutputController.getNotificationIcon()).isNull();
+ assertThat(mMediaSwitchingController.getNotificationIcon()).isNull();
}
@Test
@@ -1028,7 +1088,7 @@
when(notification.isMediaNotification()).thenReturn(true);
when(notification.getLargeIcon()).thenReturn(null);
- assertThat(mMediaOutputController.getNotificationIcon()).isNull();
+ assertThat(mMediaSwitchingController.getNotificationIcon()).isNull();
}
@Test
@@ -1047,7 +1107,7 @@
when(notification.isMediaNotification()).thenReturn(true);
when(notification.getLargeIcon()).thenReturn(icon);
- assertThat(mMediaOutputController.getNotificationIcon()).isInstanceOf(IconCompat.class);
+ assertThat(mMediaSwitchingController.getNotificationIcon()).isInstanceOf(IconCompat.class);
}
@Test
@@ -1066,7 +1126,7 @@
when(notification.isMediaNotification()).thenReturn(false);
when(notification.getLargeIcon()).thenReturn(icon);
- assertThat(mMediaOutputController.getNotificationIcon()).isNull();
+ assertThat(mMediaSwitchingController.getNotificationIcon()).isNull();
}
@Test
@@ -1084,7 +1144,7 @@
when(notification.isMediaNotification()).thenReturn(true);
when(notification.getSmallIcon()).thenReturn(null);
- assertThat(mMediaOutputController.getNotificationSmallIcon()).isNull();
+ assertThat(mMediaSwitchingController.getNotificationSmallIcon()).isNull();
}
@Test
@@ -1103,8 +1163,8 @@
when(notification.isMediaNotification()).thenReturn(true);
when(notification.getSmallIcon()).thenReturn(icon);
- assertThat(mMediaOutputController.getNotificationSmallIcon()).isInstanceOf(
- IconCompat.class);
+ assertThat(mMediaSwitchingController.getNotificationSmallIcon())
+ .isInstanceOf(IconCompat.class);
}
@Test
@@ -1112,8 +1172,8 @@
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
when(mMediaDevice1.getIcon()).thenReturn(mDrawable);
- assertThat(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).isInstanceOf(
- IconCompat.class);
+ assertThat(mMediaSwitchingController.getDeviceIconCompat(mMediaDevice1))
+ .isInstanceOf(IconCompat.class);
}
@Test
@@ -1121,13 +1181,13 @@
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
when(mMediaDevice1.getIcon()).thenReturn(null);
- assertThat(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).isInstanceOf(
- IconCompat.class);
+ assertThat(mMediaSwitchingController.getDeviceIconCompat(mMediaDevice1))
+ .isInstanceOf(IconCompat.class);
}
@Test
public void setColorFilter_setColorFilterToDrawable() {
- mMediaOutputController.setColorFilter(mDrawable, true);
+ mMediaSwitchingController.setColorFilter(mDrawable, true);
verify(mDrawable).setColorFilter(any(PorterDuffColorFilter.class));
}
@@ -1150,11 +1210,11 @@
selectableMediaDevices.add(selectableMediaDevice2);
doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice();
doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice();
- assertThat(mMediaOutputController.getGroupMediaDevices().isEmpty()).isFalse();
+ assertThat(mMediaSwitchingController.getGroupMediaDevices().isEmpty()).isFalse();
- mMediaOutputController.resetGroupMediaDevices();
+ mMediaSwitchingController.resetGroupMediaDevices();
- assertThat(mMediaOutputController.mGroupMediaDevices.isEmpty()).isTrue();
+ assertThat(mMediaSwitchingController.mGroupMediaDevices.isEmpty()).isTrue();
}
@Test
@@ -1164,7 +1224,7 @@
when(mMediaDevice1.isVolumeFixed()).thenReturn(true);
- assertThat(mMediaOutputController.isVolumeControlEnabled(mMediaDevice1)).isFalse();
+ assertThat(mMediaSwitchingController.isVolumeControlEnabled(mMediaDevice1)).isFalse();
}
@Test
@@ -1174,7 +1234,7 @@
when(mMediaDevice1.isVolumeFixed()).thenReturn(false);
- assertThat(mMediaOutputController.isVolumeControlEnabled(mMediaDevice1)).isTrue();
+ assertThat(mMediaSwitchingController.isVolumeControlEnabled(mMediaDevice1)).isTrue();
}
@Test
@@ -1187,7 +1247,7 @@
when(mMediaDevice2.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE);
- mMediaOutputController.setTemporaryAllowListExceptionIfNeeded(mMediaDevice2);
+ mMediaSwitchingController.setTemporaryAllowListExceptionIfNeeded(mMediaDevice2);
verify(mPowerExemptionManager).addToTemporaryAllowList(anyString(), anyInt(), anyString(),
anyLong());
@@ -1195,8 +1255,8 @@
@Test
public void setTemporaryAllowListExceptionIfNeeded_packageNameIsNull_NoAction() {
- MediaOutputController testMediaOutputController =
- new MediaOutputController(
+ MediaSwitchingController testMediaSwitchingController =
+ new MediaSwitchingController(
mSpyContext,
null,
mSpyContext.getUser(),
@@ -1214,7 +1274,7 @@
mVolumePanelGlobalStateInteractor,
mUserTracker);
- testMediaOutputController.setTemporaryAllowListExceptionIfNeeded(mMediaDevice2);
+ testMediaSwitchingController.setTemporaryAllowListExceptionIfNeeded(mMediaDevice2);
verify(mPowerExemptionManager, never()).addToTemporaryAllowList(anyString(), anyInt(),
anyString(),
@@ -1223,22 +1283,22 @@
@Test
public void onMetadataChanged_triggersOnMetadataChanged() {
- mMediaOutputController.mCallback = this.mCallback;
+ mMediaSwitchingController.mCallback = this.mCallback;
- mMediaOutputController.mCb.onMetadataChanged(mMediaMetadata);
+ mMediaSwitchingController.mCb.onMetadataChanged(mMediaMetadata);
- verify(mMediaOutputController.mCallback).onMediaChanged();
+ verify(mMediaSwitchingController.mCallback).onMediaChanged();
}
@Test
public void onPlaybackStateChanged_updateWithNullState_onMediaStoppedOrPaused() {
when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_PLAYING);
- mMediaOutputController.mCallback = this.mCallback;
- mMediaOutputController.start(mCb);
+ mMediaSwitchingController.mCallback = this.mCallback;
+ mMediaSwitchingController.start(mCb);
- mMediaOutputController.mCb.onPlaybackStateChanged(null);
+ mMediaSwitchingController.mCb.onPlaybackStateChanged(null);
- verify(mMediaOutputController.mCallback).onMediaStoppedOrPaused();
+ verify(mMediaSwitchingController.mCallback).onMediaStoppedOrPaused();
}
@Test
@@ -1246,9 +1306,9 @@
when(mDialogTransitionAnimator.createActivityTransitionController(mDialogLaunchView))
.thenReturn(mActivityTransitionAnimatorController);
when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
- mMediaOutputController.mCallback = this.mCallback;
+ mMediaSwitchingController.mCallback = this.mCallback;
- mMediaOutputController.launchBluetoothPairing(mDialogLaunchView);
+ mMediaSwitchingController.launchBluetoothPairing(mDialogLaunchView);
verify(mCallback).dismissDialog();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
index 1ec4814..b86d571 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt
@@ -17,8 +17,12 @@
import android.app.role.RoleManager
import android.app.role.RoleManager.ROLE_NOTES
+import android.hardware.input.InputManager
+import android.hardware.input.KeyGestureEvent
import android.os.UserHandle
import android.os.UserManager
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
import android.view.KeyEvent
import android.view.KeyEvent.ACTION_DOWN
import android.view.KeyEvent.ACTION_UP
@@ -42,6 +46,7 @@
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
@@ -57,7 +62,11 @@
@RunWith(AndroidJUnit4::class)
internal class NoteTaskInitializerTest : SysuiTestCase() {
+ @get:Rule
+ val setFlagsRule = SetFlagsRule()
+
@Mock lateinit var commandQueue: CommandQueue
+ @Mock lateinit var inputManager: InputManager
@Mock lateinit var bubbles: Bubbles
@Mock lateinit var controller: NoteTaskController
@Mock lateinit var roleManager: RoleManager
@@ -86,6 +95,7 @@
roleManager = roleManager,
userTracker = userTracker,
keyguardUpdateMonitor = keyguardMonitor,
+ inputManager = inputManager,
backgroundExecutor = executor,
)
@@ -172,6 +182,26 @@
}
@Test
+ @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
+ fun initialize_handleKeyGestureEvent() {
+ val gestureEvent = KeyGestureEvent.Builder()
+ .setKeycodes(intArrayOf(KeyEvent.KEYCODE_N))
+ .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES)
+ .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ .build()
+ val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
+ underTest.initialize()
+ val callback =
+ withArgCaptor { verify(inputManager).registerKeyGestureEventHandler(capture()) }
+
+ assertThat(callback.handleKeyGestureEvent(gestureEvent, null)).isTrue()
+
+ executor.runAllReady()
+ verify(controller).showNoteTask(any())
+ }
+
+ @Test
fun initialize_userUnlocked_shouldUpdateNoteTask() {
whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(false)
val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
index 70af5e7..755adc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt
@@ -26,7 +26,6 @@
import androidx.compose.ui.test.hasContentDescription
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onChildAt
import androidx.compose.ui.test.onChildren
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
@@ -40,6 +39,7 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.qs.panels.shared.model.SizedTile
import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.DefaultEditTileGrid
import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.shared.model.TileCategory
@@ -57,7 +57,7 @@
@Composable
private fun EditTileGridUnderTest(
listState: EditTileListState,
- onSetTiles: (List<TileSpec>) -> Unit
+ onSetTiles: (List<TileSpec>) -> Unit,
) {
DefaultEditTileGrid(
currentListState = listState,
@@ -182,7 +182,7 @@
private fun ComposeContentTestRule.assertTileGridContainsExactly(specs: List<String>) {
onNodeWithTag(CURRENT_TILES_GRID_TEST_TAG).onChildren().apply {
fetchSemanticsNodes().forEachIndexed { index, _ ->
- get(index).onChildAt(0).assert(hasContentDescription(specs[index]))
+ get(index).assert(hasContentDescription(specs[index]))
}
}
}
@@ -198,7 +198,7 @@
icon =
Icon.Resource(
android.R.drawable.star_on,
- ContentDescription.Loaded(tileSpec)
+ ContentDescription.Loaded(tileSpec),
),
label = AnnotatedString(tileSpec),
appName = null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index 2e2ac3e..a0ecb80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -231,7 +231,7 @@
"",
"",
UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
+ UserManager.USER_TYPE_PROFILE_MANAGED,
)
infoProfile.profileGroupId = id
listOf(info, infoProfile)
@@ -261,7 +261,7 @@
"",
"",
UserInfo.FLAG_MANAGED_PROFILE or UserInfo.FLAG_QUIET_MODE,
- UserManager.USER_TYPE_PROFILE_MANAGED
+ UserManager.USER_TYPE_PROFILE_MANAGED,
)
infoProfile.profileGroupId = id
listOf(info, infoProfile)
@@ -291,7 +291,7 @@
"",
"",
UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
+ UserManager.USER_TYPE_PROFILE_MANAGED,
)
infoProfile.profileGroupId = id
listOf(info, infoProfile)
@@ -423,7 +423,7 @@
"",
"",
UserInfo.FLAG_MANAGED_PROFILE,
- UserManager.USER_TYPE_PROFILE_MANAGED
+ UserManager.USER_TYPE_PROFILE_MANAGED,
)
infoProfile.profileGroupId = id
listOf(info, infoProfile)
@@ -469,6 +469,24 @@
assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
}
+ @Test
+ fun testisUserSwitching() =
+ testScope.runTest {
+ tracker.initialize(0)
+ val newID = 5
+ val profileID = newID + 10
+
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ assertThat(tracker.isUserSwitching).isFalse()
+
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+ assertThat(tracker.isUserSwitching).isTrue()
+
+ captor.value.onUserSwitchComplete(newID)
+ assertThat(tracker.isUserSwitching).isFalse()
+ }
+
private class TestCallback : UserTracker.Callback {
var calledOnUserChanging = 0
var calledOnUserChanged = 0
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 1e2648b22..ecc7909 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -20,7 +20,6 @@
import static android.media.AudioManager.RINGER_MODE_SILENT;
import static android.media.AudioManager.RINGER_MODE_VIBRATE;
-import static com.android.systemui.Flags.FLAG_HAPTIC_VOLUME_SLIDER;
import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN;
import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN;
import static com.android.systemui.volume.VolumeDialogControllerImpl.DYNAMIC_STREAM_BROADCAST;
@@ -51,7 +50,6 @@
import android.media.AudioManager;
import android.media.AudioSystem;
import android.os.SystemClock;
-import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import android.testing.TestableLooper;
@@ -285,23 +283,8 @@
}
@Test
- @DisableFlags(FLAG_HAPTIC_VOLUME_SLIDER)
- public void addSliderHaptics_withHapticsDisabled_doesNotDeliverOnProgressChangedHaptics() {
- // GIVEN that the slider haptics flag is disabled and we try to add haptics to volume rows
- mDialog.addSliderHapticsToRows();
-
- // WHEN haptics try to be delivered to a volume stream
- boolean canDeliverHaptics =
- mDialog.canDeliverProgressHapticsToStream(AudioSystem.STREAM_MUSIC, true, 50);
-
- // THEN the result is that haptics are not successfully delivered
- assertFalse(canDeliverHaptics);
- }
-
- @Test
- @EnableFlags(FLAG_HAPTIC_VOLUME_SLIDER)
- public void addSliderHaptics_withHapticsEnabled_canDeliverOnProgressChangedHaptics() {
- // GIVEN that the slider haptics flag is enabled and we try to add haptics to volume rows
+ public void addSliderHaptics_canDeliverOnProgressChangedHaptics() {
+ // GIVEN that the slider haptics are added to rows
mDialog.addSliderHapticsToRows();
// WHEN haptics try to be delivered to a volume stream
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryKosmos.kt
index 1d2bce2..1df3ef4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryKosmos.kt
@@ -19,7 +19,7 @@
import com.android.systemui.kosmos.Kosmos
import java.time.Instant
-var Kosmos.contextualEducationRepository: ContextualEducationRepository by
+var Kosmos.contextualEducationRepository: FakeContextualEducationRepository by
Kosmos.Fixture { FakeContextualEducationRepository() }
var Kosmos.fakeEduClock: FakeEduClock by Kosmos.Fixture { FakeEduClock(Instant.MIN) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt
index fb4e2fb..4667bf5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/FakeContextualEducationRepository.kt
@@ -17,39 +17,77 @@
package com.android.systemui.education.data.repository
import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.contextualeducation.GestureType.ALL_APPS
+import com.android.systemui.contextualeducation.GestureType.BACK
+import com.android.systemui.contextualeducation.GestureType.HOME
+import com.android.systemui.contextualeducation.GestureType.OVERVIEW
import com.android.systemui.education.data.model.EduDeviceConnectionTime
import com.android.systemui.education.data.model.GestureEduModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.filterNotNull
class FakeContextualEducationRepository : ContextualEducationRepository {
- private val userGestureMap = mutableMapOf<Int, GestureEduModel>()
- private val _gestureEduModels = MutableStateFlow(GestureEduModel(userId = 0))
- private val gestureEduModelsFlow = _gestureEduModels.asStateFlow()
+ private val userGestureMap = mutableMapOf<Int, MutableMap<GestureType, GestureEduModel>>()
+
+ private val _backGestureEduModels = MutableStateFlow(GestureEduModel(BACK, userId = 0))
+ private val backGestureEduModelsFlow = _backGestureEduModels.asStateFlow()
+
+ private val _homeGestureEduModels = MutableStateFlow(GestureEduModel(HOME, userId = 0))
+ private val homeEduModelsFlow = _homeGestureEduModels.asStateFlow()
+
+ private val _allAppsGestureEduModels = MutableStateFlow(GestureEduModel(ALL_APPS, userId = 0))
+ private val allAppsGestureEduModels = _allAppsGestureEduModels.asStateFlow()
+
+ private val _overviewsGestureEduModels = MutableStateFlow(GestureEduModel(OVERVIEW, userId = 0))
+ private val overviewsGestureEduModels = _overviewsGestureEduModels.asStateFlow()
private val userEduDeviceConnectionTimeMap = mutableMapOf<Int, EduDeviceConnectionTime>()
private val _eduDeviceConnectionTime = MutableStateFlow(EduDeviceConnectionTime())
private val eduDeviceConnectionTime = _eduDeviceConnectionTime.asStateFlow()
+ private val _keyboardShortcutTriggered = MutableStateFlow<GestureType?>(null)
+
private var currentUser: Int = 0
override fun setUser(userId: Int) {
if (!userGestureMap.contains(userId)) {
- userGestureMap[userId] = GestureEduModel(userId = userId)
+ userGestureMap[userId] = createGestureEduModelMap(userId = userId)
userEduDeviceConnectionTimeMap[userId] = EduDeviceConnectionTime()
}
// save data of current user to the map
- userGestureMap[currentUser] = _gestureEduModels.value
- userEduDeviceConnectionTimeMap[currentUser] = _eduDeviceConnectionTime.value
+ val currentUserMap = userGestureMap[currentUser]!!
+ currentUserMap[BACK] = _backGestureEduModels.value
+ currentUserMap[HOME] = _homeGestureEduModels.value
+ currentUserMap[ALL_APPS] = _allAppsGestureEduModels.value
+ currentUserMap[OVERVIEW] = _overviewsGestureEduModels.value
+
// switch to data of new user
- _gestureEduModels.value = userGestureMap[userId]!!
+ val newUserGestureMap = userGestureMap[userId]!!
+ newUserGestureMap[BACK]?.let { _backGestureEduModels.value = it }
+ newUserGestureMap[HOME]?.let { _homeGestureEduModels.value = it }
+ newUserGestureMap[ALL_APPS]?.let { _allAppsGestureEduModels.value = it }
+ newUserGestureMap[OVERVIEW]?.let { _overviewsGestureEduModels.value = it }
+
+ userEduDeviceConnectionTimeMap[currentUser] = _eduDeviceConnectionTime.value
_eduDeviceConnectionTime.value = userEduDeviceConnectionTimeMap[userId]!!
}
+ private fun createGestureEduModelMap(userId: Int): MutableMap<GestureType, GestureEduModel> {
+ val gestureModelMap = mutableMapOf<GestureType, GestureEduModel>()
+ GestureType.values().forEach { gestureModelMap[it] = GestureEduModel(it, userId = userId) }
+ return gestureModelMap
+ }
+
override fun readGestureEduModelFlow(gestureType: GestureType): Flow<GestureEduModel> {
- return gestureEduModelsFlow
+ return when (gestureType) {
+ BACK -> backGestureEduModelsFlow
+ HOME -> homeEduModelsFlow
+ ALL_APPS -> allAppsGestureEduModels
+ OVERVIEW -> overviewsGestureEduModels
+ }
}
override fun readEduDeviceConnectionTime(): Flow<EduDeviceConnectionTime> {
@@ -60,8 +98,16 @@
gestureType: GestureType,
transform: (GestureEduModel) -> GestureEduModel
) {
- val currentModel = _gestureEduModels.value
- _gestureEduModels.value = transform(currentModel)
+ val gestureModels =
+ when (gestureType) {
+ BACK -> _backGestureEduModels
+ HOME -> _homeGestureEduModels
+ ALL_APPS -> _allAppsGestureEduModels
+ OVERVIEW -> _overviewsGestureEduModels
+ }
+
+ val currentModel = gestureModels.value
+ gestureModels.value = transform(currentModel)
}
override suspend fun updateEduDeviceConnectionTime(
@@ -70,4 +116,11 @@
val currentModel = _eduDeviceConnectionTime.value
_eduDeviceConnectionTime.value = transform(currentModel)
}
+
+ override val keyboardShortcutTriggered: Flow<GestureType>
+ get() = _keyboardShortcutTriggered.filterNotNull()
+
+ fun setKeyboardShortcutTriggered(gestureType: GestureType) {
+ _keyboardShortcutTriggered.value = gestureType
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorKosmos.kt
index 80f6fc2..2d275f9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorKosmos.kt
@@ -40,8 +40,7 @@
touchpadRepository,
userRepository
),
- clock = fakeEduClock,
- inputManager = mockEduInputManager
+ clock = fakeEduClock
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
index c252924..c0152b26 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
@@ -17,7 +17,6 @@
package com.android.systemui.flags
import android.platform.test.annotations.EnableFlags
-import com.android.systemui.Flags.FLAG_COMPOSE_LOCKSCREEN
import com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR
import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
@@ -31,7 +30,6 @@
* that feature. It is also picked up by [SceneContainerRule] to set non-aconfig prerequisites.
*/
@EnableFlags(
- FLAG_COMPOSE_LOCKSCREEN,
FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR,
FLAG_KEYGUARD_WM_STATE_REFACTOR,
FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/FakeMSDLPlayer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/FakeMSDLPlayer.kt
index 5ad973a..2b81da3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/FakeMSDLPlayer.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/FakeMSDLPlayer.kt
@@ -20,8 +20,10 @@
import com.google.android.msdl.data.model.MSDLToken
import com.google.android.msdl.domain.InteractionProperties
import com.google.android.msdl.domain.MSDLPlayer
+import com.google.android.msdl.logging.MSDLEvent
class FakeMSDLPlayer : MSDLPlayer {
+ private val history = arrayListOf<MSDLEvent>()
var currentFeedbackLevel = FeedbackLevel.DEFAULT
var latestTokenPlayed: MSDLToken? = null
private set
@@ -34,5 +36,8 @@
override fun playToken(token: MSDLToken, properties: InteractionProperties?) {
latestTokenPlayed = token
latestPropertiesPlayed = properties
+ history.add(MSDLEvent(token, properties))
}
+
+ override fun getHistory(): List<MSDLEvent> = history
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
index ca748b66..80db1e9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.haptics.qs
+import com.android.systemui.classifier.fakeFalsingManager
import com.android.systemui.haptics.vibratorHelper
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.log.core.FakeLogBuffer
@@ -26,6 +27,7 @@
QSLongPressEffect(
vibratorHelper,
keyguardStateController,
+ fakeFalsingManager,
FakeLogBuffer.Factory.create(),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
index d920c4f..574bbcd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt
@@ -17,14 +17,12 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.domain.resolver.notifShadeSceneFamilyResolver
-import com.android.systemui.scene.domain.resolver.quickSettingsSceneFamilyResolver
import com.android.systemui.shade.domain.interactor.shadeInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -37,12 +35,9 @@
dismissInteractor = keyguardDismissInteractor,
applicationScope = testScope.backgroundScope,
sceneInteractor = { sceneInteractor },
- deviceEntryInteractor = { deviceEntryInteractor },
- quickSettingsSceneFamilyResolver = { quickSettingsSceneFamilyResolver },
- notifShadeSceneFamilyResolver = { notifShadeSceneFamilyResolver },
+ deviceUnlockedInteractor = { deviceUnlockedInteractor },
powerInteractor = powerInteractor,
alternateBouncerInteractor = alternateBouncerInteractor,
- keyguardInteractor = { keyguardInteractor },
shadeInteractor = { shadeInteractor },
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt
index ace1157..52416ba 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt
@@ -41,5 +41,6 @@
trustRepository = trustRepository,
alternateBouncerInteractor = alternateBouncerInteractor,
powerInteractor = powerInteractor,
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorKosmos.kt
deleted file mode 100644
index edbc4c1..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorKosmos.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.domain.interactor
-
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.log.core.FakeLogBuffer
-import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
-
-val Kosmos.gridConsistencyInteractor by
- Kosmos.Fixture {
- GridConsistencyInteractor(
- gridLayoutTypeInteractor,
- currentTilesInteractor,
- gridConsistencyInteractorsMap,
- noopGridConsistencyInteractor,
- FakeLogBuffer.Factory.create(),
- applicationCoroutineScope,
- )
- }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
index 34e99d3..c951642 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
@@ -27,6 +27,3 @@
val Kosmos.gridLayoutMap: Map<GridLayoutType, GridLayout> by
Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridLayout)) }
-
-var Kosmos.gridConsistencyInteractorsMap: Map<GridLayoutType, GridTypeConsistencyInteractor> by
- Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor)) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorKosmos.kt
deleted file mode 100644
index 320c2ec..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorKosmos.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2024 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.qs.panels.domain.interactor
-
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.infiniteGridConsistencyInteractor by
- Kosmos.Fixture {
- InfiniteGridConsistencyInteractor(iconTilesInteractor, fixedColumnsSizeInteractor)
- }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
index be00152..3f62b4d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt
@@ -17,7 +17,7 @@
package com.android.systemui.qs.panels.domain.interactor
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout
import com.android.systemui.qs.panels.ui.viewmodel.fixedColumnsSizeViewModel
import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelKosmos.kt
index 8fc40e4..6ced8c3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayActionsViewModelKosmos.kt
@@ -18,8 +18,12 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter
+import com.android.systemui.util.mockito.mock
+
+val Kosmos.fakeQsSceneAdapter: FakeQSSceneAdapter by Fixture { FakeQSSceneAdapter({ mock() }) }
val Kosmos.quickSettingsShadeOverlayActionsViewModel:
QuickSettingsShadeOverlayActionsViewModel by Fixture {
- QuickSettingsShadeOverlayActionsViewModel()
+ QuickSettingsShadeOverlayActionsViewModel(quickSettingsContainerViewModel)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
index d17b575..8b12425 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt
@@ -24,16 +24,10 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.scene.shared.model.SceneFamilies
-import com.android.systemui.shade.domain.interactor.shadeModeInteractor
import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.sceneFamilyResolvers: Map<SceneKey, SceneResolver>
- get() =
- mapOf(
- SceneFamilies.Home to homeSceneFamilyResolver,
- SceneFamilies.NotifShade to notifShadeSceneFamilyResolver,
- SceneFamilies.QuickSettings to quickSettingsSceneFamilyResolver,
- )
+ get() = mapOf(SceneFamilies.Home to homeSceneFamilyResolver)
val Kosmos.homeSceneFamilyResolver by
Kosmos.Fixture {
@@ -43,19 +37,3 @@
keyguardEnabledInteractor = keyguardEnabledInteractor,
)
}
-
-val Kosmos.notifShadeSceneFamilyResolver by
- Kosmos.Fixture {
- NotifShadeSceneFamilyResolver(
- applicationScope = applicationCoroutineScope,
- shadeModeInteractor = shadeModeInteractor,
- )
- }
-
-val Kosmos.quickSettingsSceneFamilyResolver by
- Kosmos.Fixture {
- QuickSettingsSceneFamilyResolver(
- applicationScope = applicationCoroutineScope,
- shadeModeInteractor = shadeModeInteractor,
- )
- }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index f3d5b7d..cd76a74 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -33,6 +33,7 @@
private var _userHandle: UserHandle = UserHandle.of(_userId),
private var _userInfo: UserInfo = mock(),
private var _userProfiles: List<UserInfo> = emptyList(),
+ private var _isUserSwitching: Boolean = false,
userContentResolverProvider: () -> ContentResolver = { MockContentResolver() },
userContext: Context = mock(),
private val onCreateCurrentUserContext: (Context) -> Context = { mock() },
@@ -51,6 +52,9 @@
override val userProfiles: List<UserInfo>
get() = _userProfiles
+ override val isUserSwitching: Boolean
+ get() = _isUserSwitching
+
// userContentResolver is lazy because Ravenwood doesn't support MockContentResolver()
// and we still want to allow people use this class for tests that don't use it.
override val userContentResolver: ContentResolver by lazy { userContentResolverProvider() }
@@ -86,11 +90,13 @@
}
fun onUserChanging(userId: Int = _userId) {
+ _isUserSwitching = true
val copy = callbacks.toList()
copy.forEach { it.onUserChanging(userId, userContext) {} }
}
fun onUserChanged(userId: Int = _userId) {
+ _isUserSwitching = false
val copy = callbacks.toList()
copy.forEach { it.onUserChanged(userId, userContext) }
}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index 0458f53..b1e6fe2 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -103,7 +103,7 @@
if (displayId == display.displayId) {
val currentRotation = display.rotation
- if (lastRotation.compareAndSet(lastRotation.get(), currentRotation)) {
+ if (lastRotation.getAndSet(currentRotation) != currentRotation) {
listeners.forEach { it.onRotationChanged(currentRotation) }
}
}
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 136738f..93cdde0 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -529,167 +529,6 @@
*/
public static Pair<PreviewExtenderImpl, ImageCaptureExtenderImpl> initializeExtension(
int extensionType) {
- if (Flags.concertModeApi()) {
- if (extensionType == CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY) {
- // Basic extensions are deprecated starting with extension version 1.5
- return new Pair<>(new PreviewExtenderImpl() {
- @Override
- public boolean isExtensionAvailable(String cameraId,
- CameraCharacteristics cameraCharacteristics) {
- return false;
- }
-
- @Override
- public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
-
- }
-
- @Override
- public androidx.camera.extensions.impl.CaptureStageImpl getCaptureStage() {
- return null;
- }
-
- @Override
- public ProcessorType getProcessorType() {
- return null;
- }
-
- @Override
- public ProcessorImpl getProcessor() {
- return null;
- }
-
- @Nullable
- @Override
- public List<Pair<Integer, Size[]>> getSupportedResolutions() {
- return null;
- }
-
- @Override
- public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
- Context context) { }
-
- @Override
- public void onDeInit() { }
-
- @Override
- public androidx.camera.extensions.impl.CaptureStageImpl onPresetSession() {
- return null;
- }
-
- @Override
- public androidx.camera.extensions.impl.CaptureStageImpl onEnableSession() {
- return null;
- }
-
- @Override
- public androidx.camera.extensions.impl.CaptureStageImpl onDisableSession() {
- return null;
- }
-
- @Override
- public int onSessionType() {
- return 0;
- }
- }, new ImageCaptureExtenderImpl() {
- @Override
- public boolean isExtensionAvailable(String cameraId,
- CameraCharacteristics cameraCharacteristics) {
- return false;
- }
-
- @Override
- public void init(String cameraId,
- CameraCharacteristics cameraCharacteristics) { }
-
- @Override
- public CaptureProcessorImpl getCaptureProcessor() {
- return null;
- }
-
- @Override
- public
- List<androidx.camera.extensions.impl.CaptureStageImpl> getCaptureStages() {
- return null;
- }
-
- @Override
- public int getMaxCaptureStage() {
- return 0;
- }
-
- @Override
- public List<Pair<Integer, Size[]>> getSupportedResolutions() {
- return null;
- }
-
- @Override
- public List<Pair<Integer, Size[]>> getSupportedPostviewResolutions(
- Size captureSize) {
- return null;
- }
-
- @Override
- public Range<Long> getEstimatedCaptureLatencyRange(
- Size captureOutputSize) {
- return null;
- }
-
- @Override
- public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
- return null;
- }
-
- @Override
- public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
- return null;
- }
-
- @Override
- public boolean isCaptureProcessProgressAvailable() {
- return false;
- }
-
- @Override
- public Pair<Long, Long> getRealtimeCaptureLatency() {
- return null;
- }
-
- @Override
- public boolean isPostviewAvailable() {
- return false;
- }
-
- @Override
- public void onInit(String cameraId,
- CameraCharacteristics cameraCharacteristics, Context context) { }
-
- @Override
- public void onDeInit() { }
-
- @Override
- public androidx.camera.extensions.impl.CaptureStageImpl onPresetSession() {
- return null;
- }
-
- @Override
- public androidx.camera.extensions.impl.CaptureStageImpl onEnableSession() {
- return null;
- }
-
- @Override
- public androidx.camera.extensions.impl.CaptureStageImpl onDisableSession() {
- return null;
- }
-
- @Override
- public int onSessionType() {
- return 0;
- }
- });
- }
- }
-
switch (extensionType) {
case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
return new Pair<>(new AutoPreviewExtenderImpl(),
@@ -714,88 +553,6 @@
* @hide
*/
public static AdvancedExtenderImpl initializeAdvancedExtensionImpl(int extensionType) {
- if (Flags.concertModeApi()) {
- if (extensionType == CameraExtensionCharacteristics.EXTENSION_EYES_FREE_VIDEOGRAPHY) {
- if (EFV_SUPPORTED) {
- return new EyesFreeVideographyAdvancedExtenderImpl();
- } else {
- return new AdvancedExtenderImpl() {
- @Override
- public boolean isExtensionAvailable(String cameraId,
- Map<String, CameraCharacteristics> characteristicsMap) {
- return false;
- }
-
- @Override
- public void init(String cameraId,
- Map<String, CameraCharacteristics> characteristicsMap) {
-
- }
-
- @Override
- public Range<Long> getEstimatedCaptureLatencyRange(String cameraId,
- Size captureOutputSize, int imageFormat) {
- return null;
- }
-
- @Override
- public Map<Integer, List<Size>> getSupportedPreviewOutputResolutions(
- String cameraId) {
- return null;
- }
-
- @Override
- public Map<Integer, List<Size>> getSupportedCaptureOutputResolutions(
- String cameraId) {
- return null;
- }
-
- @Override
- public Map<Integer, List<Size>> getSupportedPostviewResolutions(
- Size captureSize) {
- return null;
- }
-
- @Override
- public List<Size> getSupportedYuvAnalysisResolutions(String cameraId) {
- return null;
- }
-
- @Override
- public SessionProcessorImpl createSessionProcessor() {
- return null;
- }
-
- @Override
- public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
- return null;
- }
-
- @Override
- public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
- return null;
- }
-
- @Override
- public boolean isCaptureProcessProgressAvailable() {
- return false;
- }
-
- @Override
- public boolean isPostviewAvailable() {
- return false;
- }
-
- @Override
- public List<Pair<CameraCharacteristics.Key, Object>>
- getAvailableCharacteristicsKeyValues() {
- return Collections.emptyList();
- }
- };
- }
- }
- }
-
switch (extensionType) {
case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
return new AutoAdvancedExtenderImpl();
@@ -1620,7 +1377,7 @@
}
ret.outputConfigs.add(entry);
}
- if (Flags.extension10Bit() && EFV_SUPPORTED) {
+ if (EFV_SUPPORTED) {
ret.colorSpace = sessionConfig.getColorSpace();
} else {
ret.colorSpace = ColorSpaceProfiles.UNSPECIFIED;
@@ -1643,16 +1400,14 @@
CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
mSessionProcessor.deInitSession();
- if (Flags.surfaceLeakFix()) {
- if (mOutputImageCaptureSurfaceImpl.mSurface != null) {
- mOutputImageCaptureSurfaceImpl.mSurface.release();
- }
- if (mOutputPreviewSurfaceImpl.mSurface != null) {
- mOutputPreviewSurfaceImpl.mSurface.release();
- }
- if (mOutputPostviewSurfaceImpl.mSurface != null) {
- mOutputPostviewSurfaceImpl.mSurface.release();
- }
+ if (mOutputImageCaptureSurfaceImpl.mSurface != null) {
+ mOutputImageCaptureSurfaceImpl.mSurface.release();
+ }
+ if (mOutputPreviewSurfaceImpl.mSurface != null) {
+ mOutputPreviewSurfaceImpl.mSurface.release();
+ }
+ if (mOutputPostviewSurfaceImpl.mSurface != null) {
+ mOutputPostviewSurfaceImpl.mSurface.release();
}
}
@@ -2596,7 +2351,7 @@
private static CameraOutputConfig getCameraOutputConfig(Camera2OutputConfigImpl output) {
CameraOutputConfig ret = new CameraOutputConfig();
- if (Flags.extension10Bit() && EFV_SUPPORTED) {
+ if (EFV_SUPPORTED) {
ret.dynamicRangeProfile = output.getDynamicRangeProfile();
} else {
ret.dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index d0ea474..10e4f38 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -341,8 +341,10 @@
android_ravenwood_libgroup {
name: "ravenwood-runtime",
data: [
- "framework-res",
- "ravenwood-empty-res",
+ ":framework-res",
+ ":ravenwood-empty-res",
+ ":framework-platform-compat-config",
+ ":services-platform-compat-config",
],
libs: [
"100-framework-minus-apex.ravenwood",
diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING
index 7f9d9c2..d4d188d 100644
--- a/ravenwood/TEST_MAPPING
+++ b/ravenwood/TEST_MAPPING
@@ -7,30 +7,17 @@
{ "name": "RavenwoodMockitoTest_device" },
{ "name": "RavenwoodBivalentTest_device" },
+ { "name": "RavenwoodBivalentInstTest_nonself_inst" },
+ { "name": "RavenwoodBivalentInstTest_self_inst_device" },
+
// The sysui tests should match vendor/unbundled_google/packages/SystemUIGoogle/TEST_MAPPING
{
- "name": "SystemUIGoogleTests",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "SystemUIGoogleTests"
}
],
"presubmit-large": [
{
- "name": "SystemUITests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "SystemUITests"
}
],
"ravenwood-presubmit": [
@@ -138,6 +125,14 @@
"host": true
},
{
+ "name": "RavenwoodBivalentInstTest_nonself_inst",
+ "host": true
+ },
+ {
+ "name": "RavenwoodBivalentInstTest_self_inst",
+ "host": true
+ },
+ {
"name": "RavenwoodBivalentTest",
"host": true
},
@@ -164,11 +159,13 @@
{
"name": "RavenwoodServicesTest",
"host": true
- },
+ }
+ // AUTO-GENERATED-END
+ ],
+ "ravenwood-postsubmit": [
{
"name": "SystemUiRavenTests",
"host": true
}
- // AUTO-GENERATED-END
]
}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRemove.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRemove.java
index 6727327..b69c637 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRemove.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRemove.java
@@ -35,4 +35,18 @@
@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
@Retention(RetentionPolicy.CLASS)
public @interface RavenwoodRemove {
+ /**
+ * One or more classes that aren't yet supported by Ravenwood, which is why this method throws.
+ */
+ Class<?>[] blockedBy() default {};
+
+ /**
+ * General free-form description of why this method throws.
+ */
+ String reason() default "";
+
+ /**
+ * Tracking bug number, if any.
+ */
+ long bug() default 0;
}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodReplace.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodReplace.java
index 83a7b6e..57cdfd2 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodReplace.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodReplace.java
@@ -42,4 +42,9 @@
* General free-form description of why this method is being replaced.
*/
String reason() default "";
+
+ /**
+ * Tracking bug number, if any.
+ */
+ long bug() default 0;
}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
index 0bb1f39..19e6af1 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodThrow.java
@@ -43,4 +43,9 @@
* General free-form description of why this method throws.
*/
String reason() default "";
+
+ /**
+ * Tracking bug number, if any.
+ */
+ long bug() default 0;
}
diff --git a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodNoConfigNoRuleTest.java b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodNoConfigNoRuleTest.java
new file mode 100644
index 0000000..d473305
--- /dev/null
+++ b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodNoConfigNoRuleTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 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.ravenwoodtest.bivalenttest;
+
+import static org.junit.Assert.assertNotNull;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test to make sure the environment is still initialized when no config and no rules are set.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodNoConfigNoRuleTest {
+
+ @Test
+ public void testInitialization() {
+ assertNotNull(InstrumentationRegistry.getInstrumentation());
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
index 68472c1..478bead 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
@@ -15,8 +15,6 @@
*/
package android.platform.test.ravenwood;
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
-
import static org.junit.Assert.fail;
import android.os.Bundle;
@@ -27,10 +25,6 @@
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.os.RuntimeInit;
-import com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook;
-import com.android.ravenwood.common.RavenwoodCommonUtils;
-
import org.junit.runner.Description;
import org.junit.runners.model.TestClass;
@@ -50,14 +44,16 @@
}
/**
+ * Called before any code starts. Internally it will only initialize the environment once.
+ */
+ public static void performGlobalInitialization() {
+ RavenwoodRuntimeEnvironmentController.globalInitOnce();
+ }
+
+ /**
* Called when a runner starts, before the inner runner gets a chance to run.
*/
public static void onRunnerInitializing(RavenwoodAwareTestRunner runner, TestClass testClass) {
- // TODO: Move the initialization code to a better place.
-
- initOnce();
-
- // This log call also ensures the framework JNI is loaded.
Log.i(TAG, "onRunnerInitializing: testClass=" + testClass.getJavaClass()
+ " runner=" + runner);
@@ -65,33 +61,6 @@
InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
}
- private static boolean sInitialized = false;
-
- private static void initOnce() {
- if (sInitialized) {
- return;
- }
- sInitialized = true;
-
- // We haven't initialized liblog yet, so directly write to System.out here.
- RavenwoodCommonUtils.log(TAG, "initOnce()");
-
- // Make sure libandroid_runtime is loaded.
- ClassLoadHook.onClassLoaded(Log.class);
-
- // Redirect stdout/stdin to liblog.
- RuntimeInit.redirectLogStreams();
-
- // This will let AndroidJUnit4 use the original runner.
- System.setProperty("android.junit.runner",
- "androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner");
- System.setProperty(RAVENWOOD_VERSION_JAVA_SYSPROP, "1");
-
- // Do the basic set up for the android sysprops.
- RavenwoodRuntimeEnvironmentController.setSystemProperties(
- RavenwoodSystemProperties.DEFAULT_VALUES);
- }
-
/**
* Called when a whole test class is skipped.
*/
@@ -108,7 +77,7 @@
Log.v(TAG, "onBeforeInnerRunnerStart: description=" + description);
// Prepare the environment before the inner runner starts.
- RavenwoodRunnerState.forRunner(runner).enterTestClass(description);
+ runner.mState.enterTestClass(description);
}
/**
@@ -119,7 +88,7 @@
Log.v(TAG, "onAfterInnerRunnerFinished: description=" + description);
RavenwoodTestStats.getInstance().onClassFinished(description);
- RavenwoodRunnerState.forRunner(runner).exitTestClass();
+ runner.mState.exitTestClass();
}
/**
@@ -133,10 +102,10 @@
if (scope == Scope.Instance && order == Order.Outer) {
// Start of a test method.
- RavenwoodRunnerState.forRunner(runner).enterTestMethod(description);
+ runner.mState.enterTestMethod(description);
}
- final var classDescription = RavenwoodRunnerState.forRunner(runner).getClassDescription();
+ final var classDescription = runner.mState.getClassDescription();
// Class-level annotations are checked by the runner already, so we only check
// method-level annotations here.
@@ -160,11 +129,11 @@
Scope scope, Order order, Throwable th) {
Log.v(TAG, "onAfter: description=" + description + ", " + scope + ", " + order + ", " + th);
- final var classDescription = RavenwoodRunnerState.forRunner(runner).getClassDescription();
+ final var classDescription = runner.mState.getClassDescription();
if (scope == Scope.Instance && order == Order.Outer) {
// End of a test method.
- RavenwoodRunnerState.forRunner(runner).exitTestMethod();
+ runner.mState.exitTestMethod();
RavenwoodTestStats.getInstance().onTestFinished(classDescription, description,
th == null ? Result.Passed : Result.Failed);
}
@@ -214,7 +183,7 @@
Description description, RavenwoodRule rule) throws Throwable {
Log.v(TAG, "onRavenwoodRuleEnter: description=" + description);
- RavenwoodRunnerState.forRunner(runner).enterRavenwoodRule(rule);
+ runner.mState.enterRavenwoodRule(rule);
}
@@ -225,6 +194,6 @@
Description description, RavenwoodRule rule) throws Throwable {
Log.v(TAG, "onRavenwoodRuleExit: description=" + description);
- RavenwoodRunnerState.forRunner(runner).exitRavenwoodRule(rule);
+ runner.mState.exitRavenwoodRule(rule);
}
-}
\ No newline at end of file
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
new file mode 100644
index 0000000..3535cb2
--- /dev/null
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodConfigState.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 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.platform.test.ravenwood;
+
+import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.Nullable;
+import android.app.ResourcesManager;
+import android.content.res.Resources;
+import android.view.DisplayAdjustments;
+
+import java.io.File;
+import java.util.HashMap;
+
+/**
+ * Used to store various states associated with {@link RavenwoodConfig} that's inly needed
+ * in junit-impl.
+ *
+ * We don't want to put it in junit-src to avoid having to recompile all the downstream
+ * dependencies after changing this class.
+ *
+ * All members must be called from the runner's main thread.
+ */
+public class RavenwoodConfigState {
+ private static final String TAG = "RavenwoodConfigState";
+
+ private final RavenwoodConfig mConfig;
+
+ public RavenwoodConfigState(RavenwoodConfig config) {
+ mConfig = config;
+ }
+
+ /** Map from path -> resources. */
+ private final HashMap<File, Resources> mCachedResources = new HashMap<>();
+
+ /**
+ * Load {@link Resources} from an APK, with cache.
+ */
+ public Resources loadResources(@Nullable File apkPath) {
+ var cached = mCachedResources.get(apkPath);
+ if (cached != null) {
+ return cached;
+ }
+
+ var fileToLoad = apkPath != null ? apkPath : new File(RAVENWOOD_EMPTY_RESOURCES_APK);
+
+ assertTrue("File " + fileToLoad + " doesn't exist.", fileToLoad.isFile());
+
+ final String path = fileToLoad.getAbsolutePath();
+ final var emptyPaths = new String[0];
+
+ ResourcesManager.getInstance().initializeApplicationPaths(path, emptyPaths);
+
+ final var ret = ResourcesManager.getInstance().getResources(null, path,
+ emptyPaths, emptyPaths, emptyPaths,
+ emptyPaths, null, null,
+ new DisplayAdjustments().getCompatibilityInfo(),
+ RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
+
+ assertNotNull(ret);
+
+ mCachedResources.put(apkPath, ret);
+ return ret;
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
index 48bed79..239c806 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
@@ -60,6 +60,8 @@
private final File mCacheDir;
private final Supplier<Resources> mResourcesSupplier;
+ private RavenwoodContext mAppContext;
+
@GuardedBy("mLock")
private Resources mResources;
@@ -77,8 +79,8 @@
mPackageName = packageName;
mMainThread = mainThread;
mResourcesSupplier = resourcesSupplier;
- mFilesDir = createTempDir("files-dir");
- mCacheDir = createTempDir("cache-dir");
+ mFilesDir = createTempDir(packageName + "_files-dir");
+ mCacheDir = createTempDir(packageName + "_cache-dir");
// Services provided by a typical shipping device
registerService(ClipboardManager.class,
@@ -131,34 +133,35 @@
@Override
public Looper getMainLooper() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getLooper();
}
@Override
public Handler getMainThreadHandler() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getThreadHandler();
}
@Override
public Executor getMainExecutor() {
Objects.requireNonNull(mMainThread,
- "Test must request setProvideMainThread() via RavenwoodRule");
+ "Test must request setProvideMainThread() via RavenwoodConfig");
return mMainThread.getThreadExecutor();
}
@Override
public String getPackageName() {
return Objects.requireNonNull(mPackageName,
- "Test must request setPackageName() via RavenwoodRule");
+ "Test must request setPackageName() (or setTargetPackageName())"
+ + " via RavenwoodConfig");
}
@Override
public String getOpPackageName() {
return Objects.requireNonNull(mPackageName,
- "Test must request setPackageName() via RavenwoodRule");
+ "Test must request setPackageName() via RavenwoodConfig");
}
@Override
@@ -227,6 +230,15 @@
return new File(RAVENWOOD_RESOURCE_APK).getAbsolutePath();
}
+ public void setApplicationContext(RavenwoodContext appContext) {
+ mAppContext = appContext;
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return mAppContext;
+ }
+
/**
* Wrap the given {@link Supplier} to become memoized.
*
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java
new file mode 100644
index 0000000..e548611
--- /dev/null
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.platform.test.ravenwood;
+
+import com.android.ravenwood.common.RavenwoodCommonUtils;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * We use this class to load libandroid_runtime.
+ * In the future, we may load other native libraries.
+ */
+public final class RavenwoodNativeLoader {
+ public static final String CORE_NATIVE_CLASSES = "core_native_classes";
+ public static final String ICU_DATA_PATH = "icu.data.path";
+ public static final String KEYBOARD_PATHS = "keyboard_paths";
+ public static final String GRAPHICS_NATIVE_CLASSES = "graphics_native_classes";
+
+ public static final String LIBANDROID_RUNTIME_NAME = "android_runtime";
+
+ /**
+ * Classes with native methods that are backed by libandroid_runtime.
+ *
+ * See frameworks/base/core/jni/platform/host/HostRuntime.cpp
+ */
+ private static final Class<?>[] sLibandroidClasses = {
+ android.util.Log.class,
+ android.os.Parcel.class,
+ android.os.Binder.class,
+ android.content.res.ApkAssets.class,
+ android.content.res.AssetManager.class,
+ android.content.res.StringBlock.class,
+ android.content.res.XmlBlock.class,
+ };
+
+ /**
+ * Classes with native methods that are backed by libhwui.
+ *
+ * See frameworks/base/libs/hwui/apex/LayoutlibLoader.cpp
+ */
+ private static final Class<?>[] sLibhwuiClasses = {
+ android.graphics.Interpolator.class,
+ android.graphics.Matrix.class,
+ android.graphics.Path.class,
+ android.graphics.Color.class,
+ android.graphics.ColorSpace.class,
+ };
+
+ /**
+ * Extra strings needed to pass to register_android_graphics_classes().
+ *
+ * `android.graphics.Graphics` is not actually a class, so we just hardcode it here.
+ */
+ public final static String[] GRAPHICS_EXTRA_INIT_PARAMS = new String[] {
+ "android.graphics.Graphics"
+ };
+
+ private RavenwoodNativeLoader() {
+ }
+
+ private static void log(String message) {
+ System.out.println("RavenwoodNativeLoader: " + message);
+ }
+
+ private static void log(String fmt, Object... args) {
+ log(String.format(fmt, args));
+ }
+
+ private static void ensurePropertyNotSet(String key) {
+ if (System.getProperty(key) != null) {
+ throw new RuntimeException("System property \"" + key + "\" is set unexpectedly");
+ }
+ }
+
+ private static void setProperty(String key, String value) {
+ System.setProperty(key, value);
+ log("Property set: %s=\"%s\"", key, value);
+ }
+
+ private static void dumpSystemProperties() {
+ for (var prop : System.getProperties().entrySet()) {
+ log(" %s=\"%s\"", prop.getKey(), prop.getValue());
+ }
+ }
+
+ /**
+ * libandroid_runtime uses Java's system properties to decide what JNI methods to set up.
+ * Set up these properties and load the native library
+ */
+ public static void loadFrameworkNativeCode() {
+ if ("1".equals(System.getenv("RAVENWOOD_DUMP_PROPERTIES"))) {
+ log("Java system properties:");
+ dumpSystemProperties();
+ }
+
+ // Make sure these properties are not set.
+ ensurePropertyNotSet(CORE_NATIVE_CLASSES);
+ ensurePropertyNotSet(ICU_DATA_PATH);
+ ensurePropertyNotSet(KEYBOARD_PATHS);
+ ensurePropertyNotSet(GRAPHICS_NATIVE_CLASSES);
+
+ // Build the property values
+ final var joiner = Collectors.joining(",");
+ final var libandroidClasses =
+ Arrays.stream(sLibandroidClasses).map(Class::getName).collect(joiner);
+ final var libhwuiClasses = Stream.concat(
+ Arrays.stream(sLibhwuiClasses).map(Class::getName),
+ Arrays.stream(GRAPHICS_EXTRA_INIT_PARAMS)
+ ).collect(joiner);
+
+ // Load the libraries
+ setProperty(CORE_NATIVE_CLASSES, libandroidClasses);
+ setProperty(GRAPHICS_NATIVE_CLASSES, libhwuiClasses);
+ log("Loading " + LIBANDROID_RUNTIME_NAME + " for '" + libandroidClasses + "' and '"
+ + libhwuiClasses + "'");
+ RavenwoodCommonUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME);
+ }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
index d73afd4..03513ab 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.fail;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import com.android.internal.annotations.GuardedBy;
@@ -35,12 +34,11 @@
import java.util.WeakHashMap;
/**
- * Used to store various states associated with the current test runner.
+ * Used to store various states associated with the current test runner that's inly needed
+ * in junit-impl.
*
- * This class could be added to {@link RavenwoodAwareTestRunner} as a field, but we don't
- * want to put it in junit-src/ (for one, that'll cause all the downstream dependencies to be
- * rebuilt when this file is updated), so we manage it separately using a Map from each
- * {@link RavenwoodAwareTestRunner} instance to a {@link RavenwoodRunnerState}.
+ * We don't want to put it in junit-src to avoid having to recompile all the downstream
+ * dependencies after changing this class.
*
* All members must be called from the runner's main thread.
*/
@@ -51,23 +49,12 @@
private static final WeakHashMap<RavenwoodAwareTestRunner, RavenwoodRunnerState> sStates =
new WeakHashMap<>();
- /**
- * Get the instance for a given runner.
- */
- public static RavenwoodRunnerState forRunner(@NonNull RavenwoodAwareTestRunner runner) {
- synchronized (sStates) {
- var ret = sStates.get(runner);
- if (ret == null) {
- ret = new RavenwoodRunnerState(runner);
- sStates.put(runner, ret);
- }
- return ret;
- }
- }
-
private final RavenwoodAwareTestRunner mRunner;
- private RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
+ /**
+ * Ctor.
+ */
+ public RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
mRunner = runner;
}
@@ -76,6 +63,7 @@
private RavenwoodConfig mCurrentConfig;
private RavenwoodRule mCurrentRule;
+ private boolean mHasRavenwoodRule;
public Description getClassDescription() {
return mClassDescription;
@@ -84,6 +72,7 @@
public void enterTestClass(Description classDescription) throws IOException {
mClassDescription = classDescription;
+ mHasRavenwoodRule = hasRavenwoodRule(mRunner.getTestClass().getJavaClass());
mCurrentConfig = extractConfiguration(mRunner.getTestClass().getJavaClass());
if (mCurrentConfig != null) {
@@ -110,9 +99,13 @@
}
public void enterRavenwoodRule(RavenwoodRule rule) throws IOException {
+ if (!mHasRavenwoodRule) {
+ fail("If you have a RavenwoodRule in your test, make sure the field type is"
+ + " RavenwoodRule so Ravenwood can detect it.");
+ }
if (mCurrentConfig != null) {
- fail("RavenwoodConfiguration and RavenwoodRule cannot be used in the same class."
- + " Suggest migrating to RavenwoodConfiguration.");
+ fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class."
+ + " Suggest migrating to RavenwoodConfig.");
}
if (mCurrentRule != null) {
fail("Multiple nesting RavenwoodRule's are detected in the same class,"
@@ -138,16 +131,20 @@
* @return a configuration from a test class, if any.
*/
@Nullable
- private static RavenwoodConfig extractConfiguration(Class<?> testClass) {
- final boolean hasRavenwoodRule = hasRavenwoodRule(testClass);
-
+ private RavenwoodConfig extractConfiguration(Class<?> testClass) {
var field = findConfigurationField(testClass);
if (field == null) {
- return null;
+ if (mHasRavenwoodRule) {
+ // Should be handled by RavenwoodRule
+ return null;
+ }
+
+ // If no RavenwoodConfig and no RavenwoodRule, return a default config
+ return new RavenwoodConfig.Builder().build();
}
- if (hasRavenwoodRule) {
- fail("RavenwoodConfiguration and RavenwoodRule cannot be used in the same class."
- + " Suggest migrating to RavenwoodConfiguration.");
+ if (mHasRavenwoodRule) {
+ fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class."
+ + " Suggest migrating to RavenwoodConfig.");
}
try {
@@ -168,7 +165,7 @@
private static boolean hasRavenwoodRule(Class<?> testClass) {
for (var field : testClass.getDeclaredFields()) {
if (!field.isAnnotationPresent(Rule.class)
- && field.isAnnotationPresent(ClassRule.class)) {
+ && !field.isAnnotationPresent(ClassRule.class)) {
continue;
}
if (field.getType().equals(RavenwoodRule.class)) {
@@ -178,7 +175,7 @@
// JUnit supports rules as methods, so we need to check them too.
for (var method : testClass.getDeclaredMethods()) {
if (!method.isAnnotationPresent(Rule.class)
- && method.isAnnotationPresent(ClassRule.class)) {
+ && !method.isAnnotationPresent(ClassRule.class)) {
continue;
}
if (method.getReturnType().equals(RavenwoodRule.class)) {
@@ -193,8 +190,8 @@
}
/**
- * Find and return a field with @RavenwoodConfiguration.Config, which must be of type
- * RavenwoodConfiguration.
+ * Find and return a field with @RavenwoodConfig.Config, which must be of type
+ * RavenwoodConfig.
*/
@Nullable
private static Field findConfigurationField(Class<?> testClass) {
@@ -211,7 +208,7 @@
fail(String.format(
"Class %s has multiple fields with %s",
testClass.getCanonicalName(),
- "@RavenwoodConfiguration.Config"));
+ "@RavenwoodConfig.Config"));
}
// Make sure it's static public
ensureIsPublicMember(field, true);
@@ -222,8 +219,8 @@
"Field %s.%s has %s but type is not %s",
testClass.getCanonicalName(),
field.getName(),
- "@RavenwoodConfiguration.Config",
- "RavenwoodConfiguration"));
+ "@RavenwoodConfig.Config",
+ "RavenwoodConfig"));
return null; // unreachable
}
} else {
@@ -232,8 +229,8 @@
"Field %s.%s does not have %s but type is %s",
testClass.getCanonicalName(),
field.getName(),
- "@RavenwoodConfiguration.Config",
- "RavenwoodConfiguration"));
+ "@RavenwoodConfig.Config",
+ "RavenwoodConfig"));
return null; // unreachable
} else {
// Unrelated field, ignore.
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 03c9001..2417262 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -16,12 +16,11 @@
package android.platform.test.ravenwood;
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK;
import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
+import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.app.ActivityManager;
import android.app.Instrumentation;
@@ -33,11 +32,14 @@
import android.os.HandlerThread;
import android.os.Looper;
import android.os.ServiceManager;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
-import android.view.DisplayAdjustments;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.internal.os.RuntimeInit;
+import com.android.ravenwood.common.RavenwoodCommonUtils;
import com.android.ravenwood.common.RavenwoodRuntimeException;
import com.android.ravenwood.common.SneakyThrow;
import com.android.server.LocalServices;
@@ -117,6 +119,43 @@
}
private static RavenwoodConfig sConfig;
+ private static boolean sInitialized = false;
+
+ /**
+ * Initialize the global environment.
+ */
+ public static void globalInitOnce() {
+ if (sInitialized) {
+ return;
+ }
+ sInitialized = true;
+
+ // We haven't initialized liblog yet, so directly write to System.out here.
+ RavenwoodCommonUtils.log(TAG, "globalInit()");
+
+ // Do the basic set up for the android sysprops.
+ setSystemProperties(RavenwoodSystemProperties.DEFAULT_VALUES);
+
+ // Make sure libandroid_runtime is loaded.
+ RavenwoodNativeLoader.loadFrameworkNativeCode();
+
+ // Redirect stdout/stdin to liblog.
+ RuntimeInit.redirectLogStreams();
+
+ if (RAVENWOOD_VERBOSE_LOGGING) {
+ RavenwoodCommonUtils.log(TAG, "Force enabling verbose logging");
+ try {
+ Os.setenv("ANDROID_LOG_TAGS", "*:v", true);
+ } catch (ErrnoException e) {
+ // Shouldn't happen.
+ }
+ }
+
+ System.setProperty(RAVENWOOD_VERSION_JAVA_SYSPROP, "1");
+ // This will let AndroidJUnit4 use the original runner.
+ System.setProperty("android.junit.runner",
+ "androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner");
+ }
/**
* Initialize the environment.
@@ -163,31 +202,52 @@
main = null;
}
- // TODO This should be integrated into LoadedApk
- final Supplier<Resources> resourcesSupplier = () -> {
- var resApkFile = new File(RAVENWOOD_RESOURCE_APK);
- if (!resApkFile.isFile()) {
- resApkFile = new File(RAVENWOOD_EMPTY_RESOURCES_APK);
- }
- assertTrue(resApkFile.isFile());
- final String res = resApkFile.getAbsolutePath();
- final var emptyPaths = new String[0];
+ final boolean isSelfInstrumenting =
+ Objects.equals(config.mTestPackageName, config.mTargetPackageName);
- ResourcesManager.getInstance().initializeApplicationPaths(res, emptyPaths);
-
- final var ret = ResourcesManager.getInstance().getResources(null, res,
- emptyPaths, emptyPaths, emptyPaths,
- emptyPaths, null, null,
- new DisplayAdjustments().getCompatibilityInfo(),
- RavenwoodRuntimeEnvironmentController.class.getClassLoader(), null);
-
- assertNotNull(ret);
- return ret;
+ // This will load the resources from the apk set to `resource_apk` in the build file.
+ // This is supposed to be the "target app"'s resources.
+ final Supplier<Resources> targetResourcesLoader = () -> {
+ var file = new File(RAVENWOOD_RESOURCE_APK);
+ return config.mState.loadResources(file.exists() ? file : null);
};
+ // Set up test context's resources.
+ // If the target package name == test package name, then we use the main resources.
+ // Otherwise, we don't simulate loading resources from the test APK yet.
+ // (we need to add `test_resource_apk` to `android_ravenwood_test`)
+ final Supplier<Resources> testResourcesLoader;
+ if (isSelfInstrumenting) {
+ testResourcesLoader = targetResourcesLoader;
+ } else {
+ testResourcesLoader = () -> {
+ fail("Cannot load resources from the test context (yet)."
+ + " Use target context's resources instead.");
+ return null; // unreachable.
+ };
+ }
- config.mContext = new RavenwoodContext(config.mPackageName, main, resourcesSupplier);
+ var testContext = new RavenwoodContext(
+ config.mTestPackageName, main, testResourcesLoader);
+ var targetContext = new RavenwoodContext(
+ config.mTargetPackageName, main, targetResourcesLoader);
+
+ // Set up app context.
+ var appContext = new RavenwoodContext(
+ config.mTargetPackageName, main, targetResourcesLoader);
+ appContext.setApplicationContext(appContext);
+ if (isSelfInstrumenting) {
+ testContext.setApplicationContext(appContext);
+ targetContext.setApplicationContext(appContext);
+ } else {
+ // When instrumenting into another APK, the test context doesn't have an app context.
+ targetContext.setApplicationContext(appContext);
+ }
+ config.mTestContext = testContext;
+ config.mTargetContext = targetContext;
+
+ // Prepare other fields.
config.mInstrumentation = new Instrumentation();
- config.mInstrumentation.basicInit(config.mContext);
+ config.mInstrumentation.basicInit(config.mTestContext, config.mTargetContext);
InstrumentationRegistry.registerInstance(config.mInstrumentation, Bundle.EMPTY);
RavenwoodSystemServer.init(config);
@@ -224,10 +284,14 @@
InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
config.mInstrumentation = null;
- if (config.mContext != null) {
- ((RavenwoodContext) config.mContext).cleanUp();
+ if (config.mTestContext != null) {
+ ((RavenwoodContext) config.mTestContext).cleanUp();
}
- config.mContext = null;
+ if (config.mTargetContext != null) {
+ ((RavenwoodContext) config.mTargetContext).cleanUp();
+ }
+ config.mTestContext = null;
+ config.mTargetContext = null;
if (config.mProvideMainThread) {
Looper.getMainLooper().quit();
@@ -240,7 +304,9 @@
ServiceManager.reset$ravenwood();
setSystemProperties(RavenwoodSystemProperties.DEFAULT_VALUES);
- Binder.restoreCallingIdentity(sOriginalIdentityToken);
+ if (sOriginalIdentityToken != -1) {
+ Binder.restoreCallingIdentity(sOriginalIdentityToken);
+ }
android.os.Process.reset$ravenwood();
ResourcesManager.setInstance(null); // Better structure needed.
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index f3a93c1..d4090e2 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -67,7 +67,7 @@
sStartedServices = new ArraySet<>();
sTimings = new TimingsTraceAndSlog();
- sServiceManager = new SystemServiceManager(config.mContext);
+ sServiceManager = new SystemServiceManager(config.mTestContext);
sServiceManager.setStartInfo(false,
SystemClock.elapsedRealtime(),
SystemClock.uptimeMillis());
diff --git a/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
index 1adb0f3..470165c 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
@@ -51,4 +51,9 @@
* General free-form description of why this test is being ignored.
*/
String reason() default "";
+
+ /**
+ * Tracking bug number, if any.
+ */
+ long bug() default 0;
}
diff --git a/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
index 7faa654..1c06829 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
@@ -51,4 +51,9 @@
* General free-form description of why this test is being ignored.
*/
String reason() default "";
+
+ /**
+ * Tracking bug number, if any.
+ */
+ long bug() default 0;
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index bc944d7..4cb2ce1 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -46,6 +46,7 @@
import org.junit.runner.notification.RunNotifier;
import org.junit.runner.notification.StoppedByUserException;
import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.Suite;
import org.junit.runners.model.MultipleFailureException;
import org.junit.runners.model.RunnerBuilder;
import org.junit.runners.model.Statement;
@@ -170,6 +171,13 @@
private Runner mRealRunner = null;
private Description mDescription = null;
private Throwable mExceptionInConstructor = null;
+ private boolean mRealRunnerTakesRunnerBuilder = false;
+
+ /**
+ * Stores internal states / methods associated with this runner that's only needed in
+ * junit-impl.
+ */
+ final RavenwoodRunnerState mState = new RavenwoodRunnerState(this);
private Error logAndFail(String message, Throwable exception) {
Log.e(TAG, message, exception);
@@ -185,6 +193,8 @@
*/
public RavenwoodAwareTestRunner(Class<?> testClass) {
try {
+ performGlobalInitialization();
+
mTestClass = new TestClass(testClass);
Log.v(TAG, "RavenwoodAwareTestRunner starting for " + testClass.getCanonicalName());
@@ -237,7 +247,7 @@
}
}
- private static Runner instantiateRealRunner(
+ private Runner instantiateRealRunner(
Class<? extends Runner> realRunnerClass,
Class<?> testClass)
throws NoSuchMethodException, InvocationTargetException, InstantiationException,
@@ -245,12 +255,19 @@
try {
return realRunnerClass.getConstructor(Class.class).newInstance(testClass);
} catch (NoSuchMethodException e) {
- var runnerBuilder = new AllDefaultPossibilitiesBuilder();
- return realRunnerClass.getConstructor(Class.class,
- RunnerBuilder.class).newInstance(testClass, runnerBuilder);
+ var constructor = realRunnerClass.getConstructor(Class.class, RunnerBuilder.class);
+ mRealRunnerTakesRunnerBuilder = true;
+ return constructor.newInstance(testClass, new AllDefaultPossibilitiesBuilder());
}
}
+ private void performGlobalInitialization() {
+ if (!isOnRavenwood()) {
+ return;
+ }
+ RavenwoodAwareTestRunnerHook.performGlobalInitialization();
+ }
+
/**
* Run the bare minimum setup to initialize the wrapped runner.
*/
@@ -259,7 +276,6 @@
if (!isOnRavenwood()) {
return;
}
- // DO NOT USE android.util.Log before calling onRunnerInitializing().
RavenwoodAwareTestRunnerHook.onRunnerInitializing(this, mTestClass);
@@ -311,14 +327,20 @@
return;
}
+ // TODO(b/365976974): handle nested classes better
+ final boolean skipRunnerHook =
+ mRealRunnerTakesRunnerBuilder && mRealRunner instanceof Suite;
+
sCurrentRunner.set(this);
try {
- try {
- RavenwoodAwareTestRunnerHook.onBeforeInnerRunnerStart(
- this, getDescription());
- } catch (Throwable th) {
- notifier.reportBeforeTestFailure(getDescription(), th);
- return;
+ if (!skipRunnerHook) {
+ try {
+ RavenwoodAwareTestRunnerHook.onBeforeInnerRunnerStart(
+ this, getDescription());
+ } catch (Throwable th) {
+ notifier.reportBeforeTestFailure(getDescription(), th);
+ return;
+ }
}
// Delegate to the inner runner.
@@ -326,12 +348,13 @@
} finally {
sCurrentRunner.remove();
- try {
- RavenwoodAwareTestRunnerHook.onAfterInnerRunnerFinished(
- this, getDescription());
- } catch (Throwable th) {
- notifier.reportAfterTestFailure(th);
- return;
+ if (!skipRunnerHook) {
+ try {
+ RavenwoodAwareTestRunnerHook.onAfterInnerRunnerFinished(
+ this, getDescription());
+ } catch (Throwable th) {
+ notifier.reportAfterTestFailure(th);
+ }
}
}
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 04e0bed..ea33aa6 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -63,7 +63,10 @@
int mUid = NOBODY_UID;
int mPid = sNextPid.getAndIncrement();
- String mPackageName;
+ String mTestPackageName;
+ String mTargetPackageName;
+
+ int mMinSdkLevel;
boolean mProvideMainThread = false;
@@ -71,9 +74,15 @@
final List<Class<?>> mServicesRequired = new ArrayList<>();
- volatile Context mContext;
+ volatile Context mTestContext;
+ volatile Context mTargetContext;
volatile Instrumentation mInstrumentation;
+ /**
+ * Stores internal states / methods associated with this config that's only needed in
+ * junit-impl.
+ */
+ final RavenwoodConfigState mState = new RavenwoodConfigState(this);
private RavenwoodConfig() {
}
@@ -84,6 +93,12 @@
return RavenwoodRule.isOnRavenwood();
}
+ private void setDefaults() {
+ if (mTargetPackageName == null) {
+ mTargetPackageName = mTestPackageName;
+ }
+ }
+
public static class Builder {
private final RavenwoodConfig mConfig = new RavenwoodConfig();
@@ -109,11 +124,28 @@
}
/**
- * Configure the identity of this process to be the given package name for the duration
- * of the test. Has no effect on non-Ravenwood environments.
+ * Configure the package name of the test, which corresponds to
+ * {@link Instrumentation#getContext()}.
*/
public Builder setPackageName(@NonNull String packageName) {
- mConfig.mPackageName = Objects.requireNonNull(packageName);
+ mConfig.mTestPackageName = Objects.requireNonNull(packageName);
+ return this;
+ }
+
+ /**
+ * Configure the package name of the target app, which corresponds to
+ * {@link Instrumentation#getTargetContext()}. Defaults to {@link #setPackageName}.
+ */
+ public Builder setTargetPackageName(@NonNull String packageName) {
+ mConfig.mTargetPackageName = Objects.requireNonNull(packageName);
+ return this;
+ }
+
+ /**
+ * Configure the min SDK level of the test.
+ */
+ public Builder setMinSdkLevel(int sdkLevel) {
+ mConfig.mMinSdkLevel = sdkLevel;
return this;
}
@@ -178,6 +210,7 @@
}
public RavenwoodConfig build() {
+ mConfig.setDefaults();
return mConfig;
}
}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 7847e7c..984106b 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -216,7 +216,7 @@
*/
@Deprecated
public Context getContext() {
- return Objects.requireNonNull(mConfiguration.mContext,
+ return Objects.requireNonNull(mConfiguration.mTestContext,
"Context is only available during @Test execution");
}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
index 0178b93..aa8c299 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
@@ -35,6 +35,12 @@
}
/**
+ * Called before any code starts. Internally it will only initialize the environment once.
+ */
+ public static void performGlobalInitialization() {
+ }
+
+ /**
* Called when a runner starts, before the inner runner gets a chance to run.
*/
public static void onRunnerInitializing(RavenwoodAwareTestRunner runner, TestClass testClass) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
similarity index 73%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
copy to ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
index e3beff7..43a28ba 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodConfigState.java
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.platform.test.ravenwood;
-package com.android.systemui.qs.panels.domain.interactor
-
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.noopGridConsistencyInteractor by Kosmos.Fixture { NoopGridConsistencyInteractor() }
+/** Stub class. The actual implementaetion is in junit-impl-src. */
+public class RavenwoodConfigState {
+ public RavenwoodConfigState(RavenwoodConfig config) {
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
similarity index 73%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
copy to ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
index e3beff7..83cbc52 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRunnerState.java
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.platform.test.ravenwood;
-package com.android.systemui.qs.panels.domain.interactor
-
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.noopGridConsistencyInteractor by Kosmos.Fixture { NoopGridConsistencyInteractor() }
+/** Stub class. The actual implementaetion is in junit-impl-src. */
+public class RavenwoodRunnerState {
+ public RavenwoodRunnerState(RavenwoodAwareTestRunner runner) {
+ }
+}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
index 790bb1c..be8c443 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
@@ -15,54 +15,10 @@
*/
package com.android.platform.test.ravenwood.runtimehelper;
-import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
-import com.android.ravenwood.common.RavenwoodCommonUtils;
-
-import java.io.File;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-
/**
* Standard class loader hook.
- *
- * Currently, we use this class to load libandroid_runtime (if needed). In the future, we may
- * load other JNI or do other set up here.
*/
public class ClassLoadHook {
- /**
- * If true, we won't load `libandroid_runtime`
- *
- * <p>Looks like there's some complexity in running a host test with JNI with `atest`,
- * so we need a way to remove the dependency.
- */
- private static final boolean SKIP_LOADING_LIBANDROID = "1".equals(System.getenv(
- "RAVENWOOD_SKIP_LOADING_LIBANDROID"));
-
- public static final String CORE_NATIVE_CLASSES = "core_native_classes";
- public static final String ICU_DATA_PATH = "icu.data.path";
- public static final String KEYBOARD_PATHS = "keyboard_paths";
- public static final String GRAPHICS_NATIVE_CLASSES = "graphics_native_classes";
-
- public static final String LIBANDROID_RUNTIME_NAME = "android_runtime";
-
- /**
- * Extra strings needed to pass to register_android_graphics_classes().
- *
- * `android.graphics.Graphics` is not actually a class, so we can't use the same initialization
- * strategy than the "normal" classes. So we just hardcode it here.
- */
- public static final String GRAPHICS_EXTRA_INIT_PARAMS = ",android.graphics.Graphics";
-
- private static String sInitialDir = new File("").getAbsolutePath();
-
- static {
- log("Initialized. Current dir=" + sInitialDir);
- }
-
private ClassLoadHook() {
}
@@ -75,144 +31,12 @@
public static void onClassLoaded(Class<?> clazz) {
System.out.println("Framework class loaded: " + clazz.getCanonicalName());
- loadFrameworkNativeCode();
- }
-
- private static void log(String message) {
- System.out.println("ClassLoadHook: " + message);
- }
-
- private static void log(String fmt, Object... args) {
- log(String.format(fmt, args));
- }
-
- private static void ensurePropertyNotSet(String key) {
- if (System.getProperty(key) != null) {
- throw new RuntimeException("System property \"" + key + "\" is set unexpectedly");
+ // Always try to initialize the environment in case classes are loaded before
+ // RavenwoodAwareTestRunner is initialized
+ try {
+ Class.forName("android.platform.test.ravenwood.RavenwoodRuntimeEnvironmentController")
+ .getMethod("globalInitOnce").invoke(null);
+ } catch (ReflectiveOperationException ignored) {
}
}
-
- private static void setProperty(String key, String value) {
- System.setProperty(key, value);
- log("Property set: %s=\"%s\"", key, value);
- }
-
- private static void dumpSystemProperties() {
- for (var prop : System.getProperties().entrySet()) {
- log(" %s=\"%s\"", prop.getKey(), prop.getValue());
- }
- }
-
- private static boolean sLoadFrameworkNativeCodeCalled = false;
-
- /**
- * Load `libandroid_runtime` if needed.
- */
- private static void loadFrameworkNativeCode() {
- // This is called from class-initializers, so no synchronization is needed.
- if (sLoadFrameworkNativeCodeCalled) {
- return;
- }
- sLoadFrameworkNativeCodeCalled = true;
-
- // libandroid_runtime uses Java's system properties to decide what JNI methods to set up.
- // Set up these properties for host-side tests.
-
- if ("1".equals(System.getenv("RAVENWOOD_DUMP_PROPERTIES"))) {
- log("Java system properties:");
- dumpSystemProperties();
- }
-
- if (SKIP_LOADING_LIBANDROID) {
- log("Skip loading native runtime.");
- return;
- }
-
- if (RAVENWOOD_VERBOSE_LOGGING) {
- log("Force enabling verbose logging");
- try {
- Os.setenv("ANDROID_LOG_TAGS", "*:v", true);
- } catch (ErrnoException e) {
- // Shouldn't happen.
- }
- }
-
- // Make sure these properties are not set.
- ensurePropertyNotSet(CORE_NATIVE_CLASSES);
- ensurePropertyNotSet(ICU_DATA_PATH);
- ensurePropertyNotSet(KEYBOARD_PATHS);
- ensurePropertyNotSet(GRAPHICS_NATIVE_CLASSES);
-
- // Load the libraries, if needed.
- final var libanrdoidClasses = getClassesWithNativeMethods(sLibandroidClasses);
- final var libhwuiClasses = getClassesWithNativeMethods(sLibhwuiClasses);
- if (libanrdoidClasses.isEmpty() && libhwuiClasses.isEmpty()) {
- log("No classes require JNI methods, skip loading native runtime.");
- return;
- }
- setProperty(CORE_NATIVE_CLASSES, libanrdoidClasses);
- setProperty(GRAPHICS_NATIVE_CLASSES, libhwuiClasses + GRAPHICS_EXTRA_INIT_PARAMS);
-
- log("Loading " + LIBANDROID_RUNTIME_NAME + " for '" + libanrdoidClasses + "' and '"
- + libhwuiClasses + "'");
- RavenwoodCommonUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME);
- }
-
- /**
- * Classes with native methods that are backed by libandroid_runtime.
- *
- * See frameworks/base/core/jni/platform/host/HostRuntime.cpp
- */
- private static final Class<?>[] sLibandroidClasses = {
- android.util.Log.class,
- android.os.Parcel.class,
- android.os.Binder.class,
- android.content.res.ApkAssets.class,
- android.content.res.AssetManager.class,
- android.content.res.StringBlock.class,
- android.content.res.XmlBlock.class,
- };
-
- /**
- * Classes with native methods that are backed by libhwui.
- *
- * See frameworks/base/libs/hwui/apex/LayoutlibLoader.cpp
- */
- private static final Class<?>[] sLibhwuiClasses = {
- android.graphics.Interpolator.class,
- android.graphics.Matrix.class,
- android.graphics.Path.class,
- android.graphics.Color.class,
- android.graphics.ColorSpace.class,
- };
-
- /**
- * @return if a given class and its nested classes, if any, have any native method or not.
- */
- private static boolean hasNativeMethod(Class<?> clazz) {
- for (var nestedClass : clazz.getNestMembers()) {
- for (var method : nestedClass.getDeclaredMethods()) {
- if (Modifier.isNative(method.getModifiers())) {
- return true;
- }
- }
- }
- return false;
- }
- /**
- * Create a list of classes as comma-separated that require JNI methods to be set up from
- * a given class list, ignoring classes with no native methods.
- */
- private static String getClassesWithNativeMethods(Class<?>[] classes) {
- final var coreNativeClassesToLoad = new ArrayList<String>();
-
- for (var clazz : classes) {
- if (hasNativeMethod(clazz)) {
- log("Class %s has native methods", clazz.getCanonicalName());
- coreNativeClassesToLoad.add(clazz.getName());
- }
- }
-
- return String.join(",", coreNativeClassesToLoad);
- }
}
diff --git a/ravenwood/scripts/update-test-mapping.sh b/ravenwood/scripts/update-test-mapping.sh
index b6cf5b8..e478b50 100755
--- a/ravenwood/scripts/update-test-mapping.sh
+++ b/ravenwood/scripts/update-test-mapping.sh
@@ -20,6 +20,9 @@
set -e
+# Tests that shouldn't be in presubmit.
+EXEMPT='^(SystemUiRavenTests)$'
+
main() {
local script_name="${0##*/}"
local script_dir="${0%/*}"
@@ -30,7 +33,7 @@
local footer="$(sed -ne '/AUTO-GENERATED-END/,$p' "$test_mapping")"
echo "Getting all tests"
- local tests=( $("$script_dir/list-ravenwood-tests.sh") )
+ local tests=( $("$script_dir/list-ravenwood-tests.sh" | grep -vP "$EXEMPT") )
local num_tests="${#tests[@]}"
diff --git a/ravenwood/tests/bivalentinst/Android.bp b/ravenwood/tests/bivalentinst/Android.bp
new file mode 100644
index 0000000..38d1b299
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/Android.bp
@@ -0,0 +1,149 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_ravenwood_test {
+ name: "RavenwoodBivalentInstTest_self_inst",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_nonself.java",
+ ],
+
+ static_libs: [
+ "RavenwoodBivalentInstTest_self_inst_device_R",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "junit",
+ "truth",
+ ],
+ // TODO(b/366246777) uncomment it and the test.
+ // resource_apk: "RavenwoodBivalentInstTest_self_inst_device",
+ auto_gen_config: true,
+}
+
+android_ravenwood_test {
+ name: "RavenwoodBivalentInstTest_nonself_inst",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_self.java",
+ ],
+
+ static_libs: [
+ "RavenwoodBivalentInstTestTarget_R",
+ "RavenwoodBivalentInstTest_nonself_inst_device_R",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "junit",
+ "truth",
+ ],
+ // TODO(b/366246777) uncomment it and the test.
+ // resource_apk: "RavenwoodBivalentInstTestTarget",
+ auto_gen_config: true,
+}
+
+// We have 3 R.javas from the 3 packages (2 test apks below, and 1 target APK)
+// RavenwoodBivalentInstTest needs to use all of them, but we can't add all the
+// {.aapt.srcjar}'s together because that'd cause
+// "duplicate declaration of androidx.test.core.R$string."
+// So we build them as separate libraries, and include them as static_libs.
+java_library {
+ name: "RavenwoodBivalentInstTestTarget_R",
+ srcs: [
+ ":RavenwoodBivalentInstTestTarget{.aapt.srcjar}",
+ ],
+}
+
+java_library {
+ name: "RavenwoodBivalentInstTest_self_inst_device_R",
+ srcs: [
+ ":RavenwoodBivalentInstTest_self_inst_device{.aapt.srcjar}",
+ ],
+}
+
+java_library {
+ name: "RavenwoodBivalentInstTest_nonself_inst_device_R",
+ srcs: [
+ ":RavenwoodBivalentInstTest_nonself_inst_device{.aapt.srcjar}",
+ ],
+}
+
+android_test {
+ name: "RavenwoodBivalentInstTest_self_inst_device",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_nonself.java",
+ ],
+ static_libs: [
+ "junit",
+ "truth",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "ravenwood-junit",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ use_resource_processor: false,
+ manifest: "AndroidManifest-self-inst.xml",
+ test_config: "AndroidTest-self-inst.xml",
+ optimize: {
+ enabled: false,
+ },
+}
+
+android_test {
+ name: "RavenwoodBivalentInstTest_nonself_inst_device",
+
+ srcs: [
+ "test/**/*.java",
+ ],
+ exclude_srcs: [
+ "test/**/*_self.java",
+ ],
+ static_libs: [
+ "junit",
+ "truth",
+
+ "androidx.annotation_annotation",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+
+ "ravenwood-junit",
+ ],
+ data: [
+ ":RavenwoodBivalentInstTestTarget",
+ ],
+ test_suites: [
+ "device-tests",
+ ],
+ use_resource_processor: false,
+ manifest: "AndroidManifest-nonself-inst.xml",
+ test_config: "AndroidTest-nonself-inst.xml",
+ instrumentation_for: "RavenwoodBivalentInstTestTarget",
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml b/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml
new file mode 100644
index 0000000..a5a1f17
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidManifest-nonself-inst.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.ravenwood.bivalentinsttest_nonself_inst">
+
+ <application android:debuggable="true" >
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.ravenwood.bivalentinst_target_app"
+ />
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml b/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml
new file mode 100644
index 0000000..3dc4c56
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidManifest-self-inst.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.ravenwood.bivalentinsttest_self_inst">
+
+ <application android:debuggable="true" >
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.ravenwood.bivalentinsttest_self_inst"
+ />
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml b/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml
new file mode 100644
index 0000000..9491c53
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidTest-nonself-inst.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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>
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTestTarget.apk" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTest_nonself_inst_device.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.ravenwood.bivalentinsttest_nonself_inst" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml b/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml
new file mode 100644
index 0000000..3079c06
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/AndroidTest-self-inst.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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>
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="RavenwoodBivalentInstTest_self_inst_device.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.ravenwood.bivalentinsttest_self_inst" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/ravenwood/tests/bivalentinst/res/values/strings.xml b/ravenwood/tests/bivalentinst/res/values/strings.xml
new file mode 100644
index 0000000..73ef650
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string translatable="false" name="test_string_in_test">String in test APK</string>
+</resources>
diff --git a/ravenwood/tests/bivalentinst/targetapp/Android.bp b/ravenwood/tests/bivalentinst/targetapp/Android.bp
new file mode 100644
index 0000000..7528a62
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/Android.bp
@@ -0,0 +1,20 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app {
+ name: "RavenwoodBivalentInstTestTarget",
+ srcs: [
+ "src/**/*.java",
+ ],
+ sdk_version: "current",
+ optimize: {
+ enabled: false,
+ },
+ use_resource_processor: false,
+}
diff --git a/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml b/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml
new file mode 100644
index 0000000..0715f5d
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.ravenwood.bivalentinst_target_app">
+ <application>
+ </application>
+</manifest>
diff --git a/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml b/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml
new file mode 100644
index 0000000..395bc2a
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/targetapp/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string translatable="false" name="test_string_in_target">Test string in target APK</string>
+</resources>
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt b/ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
similarity index 75%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
rename to ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
index e3beff7..15e50ec 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt
+++ b/ravenwood/tests/bivalentinst/targetapp/src/com/android/ravenwoodtest/bivalentinst/Empty.java
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.ravenwoodtest.bivalentinst;
-package com.android.systemui.qs.panels.domain.interactor
-
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.noopGridConsistencyInteractor by Kosmos.Fixture { NoopGridConsistencyInteractor() }
+/**
+ * Empty class. We need it because an instrumentation target APK must have code.
+ */
+public class Empty {
+}
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
new file mode 100644
index 0000000..9f3ca6f
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_nonself.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2024 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.ravenwoodtest.bivalentinst;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodConfig;
+import android.platform.test.ravenwood.RavenwoodConfig.Config;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the case where the instrumentation target is _not_ the test APK itself.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodInstrumentationTest_nonself {
+ private static final String TARGET_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinst_target_app";
+ private static final String TEST_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_nonself_inst";
+
+ @Config
+ public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
+ .setPackageName(TEST_PACKAGE_NAME)
+ .setTargetPackageName(TARGET_PACKAGE_NAME)
+ .build();
+
+ private static Instrumentation sInstrumentation;
+ private static Context sTestContext;
+ private static Context sTargetContext;
+
+ @BeforeClass
+ public static void beforeClass() {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ sTestContext = sInstrumentation.getContext();
+ sTargetContext = sInstrumentation.getTargetContext();
+ }
+
+ @Test
+ public void testTestContextPackageName() {
+ assertThat(sTestContext.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetContextPackageName() {
+ assertThat(sTargetContext.getPackageName()).isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppContext() {
+ // Test context doesn't have an app context.
+ assertThat(sTestContext.getApplicationContext()).isNull();
+ }
+
+ @Test
+ public void testTargetAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testContextSameness() {
+ assertThat(sTargetContext).isNotSameInstanceAs(sTestContext);
+
+ assertThat(sTargetContext).isNotSameInstanceAs(sTargetContext.getApplicationContext());
+
+ assertThat(sTargetContext.getApplicationContext()).isSameInstanceAs(
+ sTargetContext.getApplicationContext().getApplicationContext());
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTargetAppResource() {
+ assertThat(sTargetContext.getString(
+ com.android.ravenwood.bivalentinst_target_app.R.string.test_string_in_target))
+ .isEqualTo("Test string in target APK");
+ }
+
+ @Test
+ @DisabledOnRavenwood(
+ reason = "Loading resources from non-self-instrumenting test APK isn't supported yet")
+ public void testTestAppResource() {
+ assertThat(sTestContext.getString(
+ com.android.ravenwood.bivalentinsttest_nonself_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+}
diff --git a/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
new file mode 100644
index 0000000..fdff222
--- /dev/null
+++ b/ravenwood/tests/bivalentinst/test/com/android/ravenwoodtest/bivalentinst/RavenwoodInstrumentationTest_self.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 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.ravenwoodtest.bivalentinst;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodConfig;
+import android.platform.test.ravenwood.RavenwoodConfig.Config;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the case where the instrumentation target is the test APK itself.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RavenwoodInstrumentationTest_self {
+
+ private static final String TARGET_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_self_inst";
+ private static final String TEST_PACKAGE_NAME =
+ "com.android.ravenwood.bivalentinsttest_self_inst";
+
+ @Config
+ public static final RavenwoodConfig sConfig = new RavenwoodConfig.Builder()
+ .setPackageName(TEST_PACKAGE_NAME)
+ .setTargetPackageName(TARGET_PACKAGE_NAME)
+ .build();
+
+
+ private static Instrumentation sInstrumentation;
+ private static Context sTestContext;
+ private static Context sTargetContext;
+
+ @BeforeClass
+ public static void beforeClass() {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ sTestContext = sInstrumentation.getContext();
+ sTargetContext = sInstrumentation.getTargetContext();
+ }
+
+ @Test
+ public void testTestContextPackageName() {
+ assertThat(sTestContext.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetContextPackageName() {
+ assertThat(sTargetContext.getPackageName()).isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppContextPackageName() {
+ assertThat(sTestContext.getApplicationContext().getPackageName())
+ .isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTestAppAppContextPackageName() {
+ assertThat(sTestContext.getApplicationContext().getPackageName())
+ .isEqualTo(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testTargetAppAppContextPackageName() {
+ assertThat(sTargetContext.getApplicationContext()
+ .getApplicationContext().getPackageName())
+ .isEqualTo(TARGET_PACKAGE_NAME);
+ }
+
+ @Test
+ public void testContextSameness() {
+ assertThat(sTargetContext).isNotSameInstanceAs(sTestContext);
+
+ assertThat(sTestContext).isNotSameInstanceAs(sTestContext.getApplicationContext());
+ assertThat(sTargetContext).isNotSameInstanceAs(sTargetContext.getApplicationContext());
+
+ assertThat(sTestContext.getApplicationContext()).isSameInstanceAs(
+ sTestContext.getApplicationContext().getApplicationContext());
+ assertThat(sTargetContext.getApplicationContext()).isSameInstanceAs(
+ sTargetContext.getApplicationContext().getApplicationContext());
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTargetAppResource() {
+ assertThat(sTargetContext.getString(
+ com.android.ravenwood.bivalentinsttest_self_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+
+ @Test
+ @DisabledOnRavenwood(reason = "b/366246777")
+ public void testTestAppResource() {
+ assertThat(sTestContext.getString(
+ com.android.ravenwood.bivalentinsttest_self_inst.R.string.test_string_in_test))
+ .isEqualTo("String in test APK");
+ }
+}
diff --git a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
index 6ee443f..73ea64f 100644
--- a/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
+++ b/ravenwood/tests/coretest/test/com/android/ravenwoodtest/runnercallbacktests/RavenwoodRunnerConfigValidationTest.java
@@ -146,7 +146,7 @@
testRunStarted: classes
testSuiteStarted: classes
testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateConfigTest)
- testFailure: Class com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.DuplicateConfigTest has multiple fields with @RavenwoodConfiguration.Config
+ testFailure: Class com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.DuplicateConfigTest has multiple fields with @RavenwoodConfig.Config
testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateConfigTest)
testSuiteFinished: classes
testRunFinished: 1,1,0,0
@@ -220,7 +220,7 @@
}
/**
- * @Config's must be of type RavenwoodConfiguration.
+ * @Config's must be of type RavenwoodConfig.
*/
@RunWith(AndroidJUnit4.class)
// CHECKSTYLE:OFF
@@ -228,7 +228,7 @@
testRunStarted: classes
testSuiteStarted: classes
testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeConfigTest)
- testFailure: Field com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.WrongTypeConfigTest.sConfig has @RavenwoodConfiguration.Config but type is not RavenwoodConfiguration
+ testFailure: Field com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.WrongTypeConfigTest.sConfig has @RavenwoodConfig.Config but type is not RavenwoodConfig
testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeConfigTest)
testSuiteFinished: classes
testRunFinished: 1,1,0,0
@@ -237,7 +237,7 @@
public static class WrongTypeConfigTest {
@RavenwoodConfig.Config
- public Object sConfig =
+ public static Object sConfig =
new RavenwoodConfig.Builder().build();
@Test
@@ -247,6 +247,34 @@
}
/**
+ * @Rule must be of type RavenwoodRule.
+ */
+ @RunWith(AndroidJUnit4.class)
+ // CHECKSTYLE:OFF
+ @Expected("""
+ testRunStarted: classes
+ testSuiteStarted: classes
+ testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest
+ testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest)
+ testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
+ testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest)
+ testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest
+ testSuiteFinished: classes
+ testRunFinished: 1,1,0,0
+ """)
+ // CHECKSTYLE:ON
+ public static class WrongTypeRuleTest {
+
+ @Rule
+ public TestRule mRule = new RavenwoodRule.Builder().build();
+
+ @Test
+ public void testConfig() {
+ }
+
+ }
+
+ /**
* Config can't be used with a (instance) Rule.
*/
@RunWith(AndroidJUnit4.class)
@@ -255,7 +283,7 @@
testRunStarted: classes
testSuiteStarted: classes
testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WithInstanceRuleTest)
- testFailure: RavenwoodConfiguration and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfiguration.
+ testFailure: RavenwoodConfig and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfig.
testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WithInstanceRuleTest)
testSuiteFinished: classes
testRunFinished: 1,1,0,0
@@ -373,7 +401,7 @@
testRunStarted: classes
testSuiteStarted: classes
testStarted: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleInBaseClassTest)
- testFailure: RavenwoodConfiguration and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfiguration.
+ testFailure: RavenwoodConfig and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfig.
testFinished: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleInBaseClassTest)
testSuiteFinished: classes
testRunFinished: 1,1,0,0
@@ -408,10 +436,11 @@
testSuiteStarted: classes
testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
testStarted: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
+ testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
testFinished: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
testSuiteFinished: classes
- testRunFinished: 1,0,0,0
+ testRunFinished: 1,1,0,0
""")
// CHECKSTYLE:ON
public static class RuleWithDifferentTypeInBaseClassSuccessTest extends RuleWithDifferentTypeInBaseClass {
@@ -434,7 +463,7 @@
testSuiteStarted: classes
testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest
testStarted: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest)
- testFailure: RavenwoodConfiguration and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfiguration.
+ testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
testFinished: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest)
testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest
testSuiteFinished: classes
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
index a38512e..f7f9a85 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Ravenizer.kt
@@ -127,7 +127,7 @@
}
}
- stats.totalProcessTime = log.iTime("$executableName processing $inJar") {
+ stats.totalProcessTime = log.vTime("$executableName processing $inJar") {
ZipFile(inJar).use { inZip ->
val inEntries = inZip.entries()
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
index e8341e5..10fe0a3 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
@@ -20,6 +20,20 @@
import com.android.hoststubgen.SetOnce
import com.android.hoststubgen.ensureFileExists
import com.android.hoststubgen.log
+import java.nio.file.Paths
+import kotlin.io.path.exists
+
+/**
+ * If this file exits, we also read options from it. This is "unsafe" because it could break
+ * incremental builds, if it sets any flag that affects the output file.
+ * (however, for now, there's no such options.)
+ *
+ * For example, to enable verbose logging, do `echo '-v' > ~/.raveniezr-unsafe`
+ *
+ * (but even the content of this file changes, soong won't rerun the command, so you need to
+ * remove the output first and then do a build again.)
+ */
+private val RAVENIZER_DOTFILE = System.getenv("HOME") + "/.raveniezr-unsafe"
class RavenizerOptions(
/** Input jar file*/
@@ -35,9 +49,16 @@
var fatalValidation: SetOnce<Boolean> = SetOnce(false),
) {
companion object {
- fun parseArgs(args: Array<String>): RavenizerOptions {
+
+ fun parseArgs(origArgs: Array<String>): RavenizerOptions {
+ val args = origArgs.toMutableList()
+ if (Paths.get(RAVENIZER_DOTFILE).exists()) {
+ log.i("Reading options from $RAVENIZER_DOTFILE")
+ args.add(0, "@$RAVENIZER_DOTFILE")
+ }
+
val ret = RavenizerOptions()
- val ai = ArgIterator.withAtFiles(args)
+ val ai = ArgIterator.withAtFiles(args.toTypedArray())
while (true) {
val arg = ai.nextArgOptional()
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
index bd9d96d..cf6d6f6 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/adapter/RunnerRewritingAdapter.kt
@@ -184,7 +184,7 @@
av.visit("value", ravenwoodTestRunnerType.type)
av.visitEnd()
}
- log.i("Update the @RunWith: ${classInternalName.toHumanReadableClassName()}")
+ log.v("Update the @RunWith: ${classInternalName.toHumanReadableClassName()}")
}
/*
@@ -442,7 +442,7 @@
// Don't process a class if it has a @NoRavenizer annotation.
classes.findClass(className)?.let { cn ->
if (cn.findAnyAnnotation(noRavenizerAnotType.descAsSet) != null) {
- log.w("Class ${className.toHumanReadableClassName()} has" +
+ log.i("Class ${className.toHumanReadableClassName()} has" +
" @${noRavenizerAnotType.humanReadableName}. Skipping."
)
return false
diff --git a/services/appfunctions/TEST_MAPPING b/services/appfunctions/TEST_MAPPING
index 91e82ec..91cfa06 100644
--- a/services/appfunctions/TEST_MAPPING
+++ b/services/appfunctions/TEST_MAPPING
@@ -1,4 +1,9 @@
{
+ "presubmit": [
+ {
+ "name": "FrameworksAppFunctionsTests"
+ }
+ ],
"postsubmit": [
{
"name": "FrameworksAppFunctionsTests"
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
index c3b7087..1f98334 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java
@@ -16,7 +16,15 @@
package com.android.server.appfunctions;
+import android.annotation.NonNull;
+import android.os.UserHandle;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -33,5 +41,50 @@
/* unit= */ TimeUnit.SECONDS,
/* workQueue= */ new LinkedBlockingQueue<>());
+ /** A map of per-user executors for queued work. */
+ @GuardedBy("sLock")
+ private static final SparseArray<ExecutorService> mPerUserExecutorsLocked = new SparseArray<>();
+
+ private static final Object sLock = new Object();
+
+ /**
+ * Returns a per-user executor for queued metadata sync request.
+ *
+ * <p>The work submitted to these executor (Sync request) needs to be synchronous per user hence
+ * the use of a single thread.
+ *
+ * <p>Note: Use a different executor if not calling {@code submitSyncRequest} on a {@code
+ * MetadataSyncAdapter}.
+ */
+ // TODO(b/357551503): Restrict the scope of this executor to the MetadataSyncAdapter itself.
+ public static ExecutorService getPerUserSyncExecutor(@NonNull UserHandle user) {
+ synchronized (sLock) {
+ ExecutorService executor = mPerUserExecutorsLocked.get(user.getIdentifier(), null);
+ if (executor == null) {
+ executor = Executors.newSingleThreadExecutor();
+ mPerUserExecutorsLocked.put(user.getIdentifier(), executor);
+ }
+ return executor;
+ }
+ }
+
+ /**
+ * Shuts down and removes the per-user executor for queued work.
+ *
+ * <p>This should be called when the user is removed.
+ */
+ public static void shutDownAndRemoveUserExecutor(@NonNull UserHandle user)
+ throws InterruptedException {
+ ExecutorService executor;
+ synchronized (sLock) {
+ executor = mPerUserExecutorsLocked.get(user.getIdentifier());
+ mPerUserExecutorsLocked.remove(user.getIdentifier());
+ }
+ if (executor != null) {
+ executor.shutdown();
+ var unused = executor.awaitTermination(30, TimeUnit.SECONDS);
+ }
+ }
+
private AppFunctionExecutors() {}
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
index 02800cb..c293087 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.appfunctions;
+import android.annotation.NonNull;
import android.app.appfunctions.AppFunctionManagerConfiguration;
import android.content.Context;
@@ -36,4 +37,14 @@
publishBinderService(Context.APP_FUNCTION_SERVICE, mServiceImpl);
}
}
+
+ @Override
+ public void onUserUnlocked(@NonNull TargetUser user) {
+ mServiceImpl.onUserUnlocked(user);
+ }
+
+ @Override
+ public void onUserStopping(@NonNull TargetUser user) {
+ mServiceImpl.onUserStopping(user);
+ }
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index 269419f..cf039df 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -19,28 +19,35 @@
import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.appfunctions.AppFunctionStaticMetadataHelper;
import android.app.appfunctions.ExecuteAppFunctionAidlRequest;
import android.app.appfunctions.ExecuteAppFunctionResponse;
import android.app.appfunctions.IAppFunctionManager;
import android.app.appfunctions.IAppFunctionService;
import android.app.appfunctions.IExecuteAppFunctionCallback;
import android.app.appfunctions.SafeOneTimeExecuteAppFunctionCallback;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.observer.DocumentChangeInfo;
+import android.app.appsearch.observer.ObserverCallback;
+import android.app.appsearch.observer.ObserverSpec;
+import android.app.appsearch.observer.SchemaChangeInfo;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Slog;
-import android.app.appsearch.AppSearchResult;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService.TargetUser;
import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback;
import com.android.server.appfunctions.RemoteServiceCaller.ServiceUsageCompleteListener;
+import java.io.IOException;
import java.util.Objects;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.CompletionException;
/** Implementation of the AppFunctionManagerService. */
public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
@@ -50,9 +57,11 @@
private final CallerValidator mCallerValidator;
private final ServiceHelper mInternalServiceHelper;
private final ServiceConfig mServiceConfig;
+ private final Context mContext;
public AppFunctionManagerServiceImpl(@NonNull Context context) {
this(
+ context,
new RemoteServiceCallerImpl<>(
context, IAppFunctionService.Stub::asInterface, THREAD_POOL_EXECUTOR),
new CallerValidatorImpl(context),
@@ -62,10 +71,12 @@
@VisibleForTesting
AppFunctionManagerServiceImpl(
+ Context context,
RemoteServiceCaller<IAppFunctionService> remoteServiceCaller,
CallerValidator callerValidator,
ServiceHelper appFunctionInternalServiceHelper,
ServiceConfig serviceConfig) {
+ mContext = Objects.requireNonNull(context);
mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller);
mCallerValidator = Objects.requireNonNull(callerValidator);
mInternalServiceHelper = Objects.requireNonNull(appFunctionInternalServiceHelper);
@@ -89,6 +100,26 @@
}
}
+ /** Called when the user is unlocked. */
+ public void onUserUnlocked(TargetUser user) {
+ Objects.requireNonNull(user);
+
+ registerAppSearchObserver(user);
+ trySyncRuntimeMetadata(user);
+ }
+
+ /** Called when the user is stopping. */
+ public void onUserStopping(@NonNull TargetUser user) {
+ Objects.requireNonNull(user);
+
+ try {
+ AppFunctionExecutors.shutDownAndRemoveUserExecutor(user.getUserHandle());
+ MetadataSyncPerUser.removeUserSyncAdapter(user.getUserHandle());
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Unable to remove data for: " + user.getUserHandle(), e);
+ }
+ }
+
private void executeAppFunctionInternal(
ExecuteAppFunctionAidlRequest requestInternal,
SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback) {
@@ -131,53 +162,55 @@
return;
}
- var unused = mCallerValidator
- .verifyCallerCanExecuteAppFunction(
- validatedCallingPackage,
- targetPackageName,
- requestInternal.getClientRequest().getFunctionIdentifier())
- .thenAccept(
- canExecute -> {
- if (!canExecute) {
- safeExecuteAppFunctionCallback.onResult(
- ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_DENIED,
- "Caller does not have permission to execute the"
- + " appfunction",
- /* extras= */ null));
- return;
- }
- Intent serviceIntent =
- mInternalServiceHelper.resolveAppFunctionService(
- targetPackageName, targetUser);
- if (serviceIntent == null) {
- safeExecuteAppFunctionCallback.onResult(
- ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
- "Cannot find the target service.",
- /* extras= */ null));
- return;
- }
- final long token = Binder.clearCallingIdentity();
- try {
- bindAppFunctionServiceUnchecked(
- requestInternal,
- serviceIntent,
- targetUser,
- safeExecuteAppFunctionCallback,
- /* bindFlags= */ Context.BIND_AUTO_CREATE,
- /* timeoutInMillis= */ mServiceConfig
- .getExecuteAppFunctionTimeoutMillis());
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- })
- .exceptionally(
- ex -> {
- safeExecuteAppFunctionCallback.onResult(
- mapExceptionToExecuteAppFunctionResponse(ex));
- return null;
- });
+ var unused =
+ mCallerValidator
+ .verifyCallerCanExecuteAppFunction(
+ validatedCallingPackage,
+ targetPackageName,
+ requestInternal.getClientRequest().getFunctionIdentifier())
+ .thenAccept(
+ canExecute -> {
+ if (!canExecute) {
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_DENIED,
+ "Caller does not have permission to execute"
+ + " the appfunction",
+ /* extras= */ null));
+ return;
+ }
+ Intent serviceIntent =
+ mInternalServiceHelper.resolveAppFunctionService(
+ targetPackageName, targetUser);
+ if (serviceIntent == null) {
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse
+ .RESULT_INTERNAL_ERROR,
+ "Cannot find the target service.",
+ /* extras= */ null));
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ bindAppFunctionServiceUnchecked(
+ requestInternal,
+ serviceIntent,
+ targetUser,
+ safeExecuteAppFunctionCallback,
+ /* bindFlags= */ Context.BIND_AUTO_CREATE,
+ /* timeoutInMillis= */ mServiceConfig
+ .getExecuteAppFunctionTimeoutMillis());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ })
+ .exceptionally(
+ ex -> {
+ safeExecuteAppFunctionCallback.onResult(
+ mapExceptionToExecuteAppFunctionResponse(ex));
+ return null;
+ });
}
private void bindAppFunctionServiceUnchecked(
@@ -255,6 +288,10 @@
}
private ExecuteAppFunctionResponse mapExceptionToExecuteAppFunctionResponse(Throwable e) {
+ if (e instanceof CompletionException) {
+ e = e.getCause();
+ }
+
if (e instanceof AppSearchException) {
AppSearchException appSearchException = (AppSearchException) e;
return ExecuteAppFunctionResponse.newFailure(
@@ -286,4 +323,103 @@
}
return ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR;
}
+
+ private void registerAppSearchObserver(@NonNull TargetUser user) {
+ AppSearchManager perUserAppSearchManager =
+ mContext.createContextAsUser(user.getUserHandle(), /* flags= */ 0)
+ .getSystemService(AppSearchManager.class);
+ if (perUserAppSearchManager == null) {
+ Slog.d(TAG, "AppSearch Manager not found for user: " + user.getUserIdentifier());
+ return;
+ }
+ try (FutureGlobalSearchSession futureGlobalSearchSession =
+ new FutureGlobalSearchSession(
+ perUserAppSearchManager, AppFunctionExecutors.THREAD_POOL_EXECUTOR)) {
+ AppFunctionMetadataObserver appFunctionMetadataObserver =
+ new AppFunctionMetadataObserver(
+ user.getUserHandle(),
+ mContext.createContextAsUser(user.getUserHandle(), /* flags= */ 0));
+ var unused =
+ futureGlobalSearchSession
+ .registerObserverCallbackAsync(
+ "android",
+ new ObserverSpec.Builder().build(),
+ THREAD_POOL_EXECUTOR,
+ appFunctionMetadataObserver)
+ .whenComplete(
+ (voidResult, ex) -> {
+ if (ex != null) {
+ Slog.e(TAG, "Failed to register observer: ", ex);
+ }
+ });
+
+ } catch (IOException ex) {
+ Slog.e(TAG, "Failed to close observer session: ", ex);
+ }
+ }
+
+ private void trySyncRuntimeMetadata(@NonNull TargetUser user) {
+ MetadataSyncAdapter metadataSyncAdapter =
+ MetadataSyncPerUser.getPerUserMetadataSyncAdapter(
+ user.getUserHandle(),
+ mContext.createContextAsUser(user.getUserHandle(), /* flags= */ 0));
+ if (metadataSyncAdapter != null) {
+ var unused =
+ metadataSyncAdapter
+ .submitSyncRequest()
+ .whenComplete(
+ (isSuccess, ex) -> {
+ if (ex != null || !isSuccess) {
+ Slog.e(TAG, "Sync was not successful");
+ }
+ });
+ }
+ }
+
+ private static class AppFunctionMetadataObserver implements ObserverCallback {
+ @Nullable private final MetadataSyncAdapter mPerUserMetadataSyncAdapter;
+
+ AppFunctionMetadataObserver(@NonNull UserHandle userHandle, @NonNull Context userContext) {
+ mPerUserMetadataSyncAdapter =
+ MetadataSyncPerUser.getPerUserMetadataSyncAdapter(userHandle, userContext);
+ }
+
+ @Override
+ public void onDocumentChanged(@NonNull DocumentChangeInfo documentChangeInfo) {
+ if (mPerUserMetadataSyncAdapter == null) {
+ return;
+ }
+ if (documentChangeInfo
+ .getDatabaseName()
+ .equals(AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_METADATA_DB)
+ && documentChangeInfo
+ .getNamespace()
+ .equals(
+ AppFunctionStaticMetadataHelper
+ .APP_FUNCTION_STATIC_NAMESPACE)) {
+ var unused = mPerUserMetadataSyncAdapter.submitSyncRequest();
+ }
+ }
+
+ @Override
+ public void onSchemaChanged(@NonNull SchemaChangeInfo schemaChangeInfo) {
+ if (mPerUserMetadataSyncAdapter == null) {
+ return;
+ }
+ if (schemaChangeInfo
+ .getDatabaseName()
+ .equals(AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_METADATA_DB)) {
+ boolean shouldInitiateSync = false;
+ for (String schemaName : schemaChangeInfo.getChangedSchemaNames()) {
+ if (schemaName.startsWith(AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE)) {
+ shouldInitiateSync = true;
+ break;
+ }
+ }
+ if (shouldInitiateSync) {
+ var unused = mPerUserMetadataSyncAdapter.submitSyncRequest();
+ }
+ }
+ }
+ }
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
index 56f373d..0044b4b 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
@@ -75,7 +75,7 @@
* AppSearchSession} database.
*/
AndroidFuture<AppSearchBatchResult<String, GenericDocument>> getByDocumentId(
- GetByDocumentIdRequest getRequest);
+ @NonNull GetByDocumentIdRequest getRequest);
/**
* Retrieves documents from the open {@link AppSearchSession} that match a given query string
diff --git a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
index 5f60804..8c6f50e 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncAdapter.java
@@ -24,6 +24,8 @@
import android.app.appfunctions.AppFunctionRuntimeMetadata;
import android.app.appfunctions.AppFunctionStaticMetadataHelper;
import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchManager;
+import android.app.appsearch.AppSearchManager.SearchContext;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.PackageIdentifier;
@@ -61,8 +63,8 @@
*/
public class MetadataSyncAdapter {
private static final String TAG = MetadataSyncAdapter.class.getSimpleName();
- private final FutureAppSearchSession mFutureAppSearchSession;
private final Executor mSyncExecutor;
+ private final AppSearchManager mAppSearchManager;
private final PackageManager mPackageManager;
// Hidden constants in {@link SetSchemaRequest} that restricts runtime metadata visibility
@@ -72,11 +74,11 @@
public MetadataSyncAdapter(
@NonNull Executor syncExecutor,
- @NonNull FutureAppSearchSession futureAppSearchSession,
- @NonNull PackageManager packageManager) {
+ @NonNull PackageManager packageManager,
+ @NonNull AppSearchManager appSearchManager) {
mSyncExecutor = Objects.requireNonNull(syncExecutor);
- mFutureAppSearchSession = Objects.requireNonNull(futureAppSearchSession);
mPackageManager = Objects.requireNonNull(packageManager);
+ mAppSearchManager = Objects.requireNonNull(appSearchManager);
}
/**
@@ -86,29 +88,54 @@
* synchronization was successful.
*/
public AndroidFuture<Boolean> submitSyncRequest() {
+ SearchContext staticMetadataSearchContext =
+ new SearchContext.Builder(
+ AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_METADATA_DB)
+ .build();
+ SearchContext runtimeMetadataSearchContext =
+ new SearchContext.Builder(
+ AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_METADATA_DB)
+ .build();
AndroidFuture<Boolean> settableSyncStatus = new AndroidFuture<>();
mSyncExecutor.execute(
() -> {
- try {
- trySyncAppFunctionMetadataBlocking();
+ try (FutureAppSearchSession staticMetadataSearchSession =
+ new FutureAppSearchSessionImpl(
+ mAppSearchManager,
+ AppFunctionExecutors.THREAD_POOL_EXECUTOR,
+ staticMetadataSearchContext);
+ FutureAppSearchSession runtimeMetadataSearchSession =
+ new FutureAppSearchSessionImpl(
+ mAppSearchManager,
+ AppFunctionExecutors.THREAD_POOL_EXECUTOR,
+ runtimeMetadataSearchContext)) {
+
+ trySyncAppFunctionMetadataBlocking(
+ staticMetadataSearchSession, runtimeMetadataSearchSession);
settableSyncStatus.complete(true);
- } catch (Exception e) {
- settableSyncStatus.completeExceptionally(e);
+
+ } catch (Exception ex) {
+ settableSyncStatus.completeExceptionally(ex);
}
});
return settableSyncStatus;
}
@WorkerThread
- private void trySyncAppFunctionMetadataBlocking()
+ @VisibleForTesting
+ void trySyncAppFunctionMetadataBlocking(
+ @NonNull FutureAppSearchSession staticMetadataSearchSession,
+ @NonNull FutureAppSearchSession runtimeMetadataSearchSession)
throws ExecutionException, InterruptedException {
ArrayMap<String, ArraySet<String>> staticPackageToFunctionMap =
getPackageToFunctionIdMap(
+ staticMetadataSearchSession,
AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME);
ArrayMap<String, ArraySet<String>> runtimePackageToFunctionMap =
getPackageToFunctionIdMap(
+ runtimeMetadataSearchSession,
RUNTIME_SCHEMA_TYPE,
AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME);
@@ -129,7 +156,7 @@
RemoveByDocumentIdRequest removeByDocumentIdRequest =
buildRemoveRuntimeMetadataRequest(removedFunctionsDiffMap);
AppSearchBatchResult<String, Void> removeDocumentBatchResult =
- mFutureAppSearchSession.remove(removeByDocumentIdRequest).get();
+ runtimeMetadataSearchSession.remove(removeByDocumentIdRequest).get();
if (!removeDocumentBatchResult.isSuccess()) {
throw convertFailedAppSearchResultToException(
removeDocumentBatchResult.getFailures().values());
@@ -139,12 +166,14 @@
if (!addedFunctionsDiffMap.isEmpty()) {
// TODO(b/357551503): only set schema on package diff
SetSchemaRequest addSetSchemaRequest =
- buildSetSchemaRequestForRuntimeMetadataSchemas(appRuntimeMetadataSchemas);
- Objects.requireNonNull(mFutureAppSearchSession.setSchema(addSetSchemaRequest).get());
+ buildSetSchemaRequestForRuntimeMetadataSchemas(
+ mPackageManager, appRuntimeMetadataSchemas);
+ Objects.requireNonNull(
+ runtimeMetadataSearchSession.setSchema(addSetSchemaRequest).get());
PutDocumentsRequest putDocumentsRequest =
buildPutRuntimeMetadataRequest(addedFunctionsDiffMap);
AppSearchBatchResult<String, Void> putDocumentBatchResult =
- mFutureAppSearchSession.put(putDocumentsRequest).get();
+ runtimeMetadataSearchSession.put(putDocumentsRequest).get();
if (!putDocumentBatchResult.isSuccess()) {
throw convertFailedAppSearchResultToException(
putDocumentBatchResult.getFailures().values());
@@ -174,11 +203,7 @@
ArraySet<String> addedFunctionIds = addedFunctionsDiffMap.valueAt(i);
for (String addedFunctionId : addedFunctionIds) {
putDocumentRequestBuilder.addGenericDocuments(
- new AppFunctionRuntimeMetadata.Builder(
- packageName,
- addedFunctionId,
- AppFunctionRuntimeMetadata
- .PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+ new AppFunctionRuntimeMetadata.Builder(packageName, addedFunctionId)
.build());
}
}
@@ -209,6 +234,7 @@
@NonNull
private SetSchemaRequest buildSetSchemaRequestForRuntimeMetadataSchemas(
+ @NonNull PackageManager packageManager,
@NonNull Set<AppSearchSchema> metadataSchemaSet) {
Objects.requireNonNull(metadataSchemaSet);
SetSchemaRequest.Builder setSchemaRequestBuilder =
@@ -218,7 +244,7 @@
String packageName =
AppFunctionRuntimeMetadata.getPackageNameFromSchema(
runtimeMetadataSchema.getSchemaType());
- byte[] packageCert = getCertificate(packageName);
+ byte[] packageCert = getCertificate(packageManager, packageName);
if (packageCert == null) {
continue;
}
@@ -226,12 +252,11 @@
runtimeMetadataSchema.getSchemaType(),
true,
new PackageIdentifier(packageName, packageCert));
+ setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+ runtimeMetadataSchema.getSchemaType(), Set.of(EXECUTE_APP_FUNCTIONS));
+ setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
+ runtimeMetadataSchema.getSchemaType(), Set.of(EXECUTE_APP_FUNCTIONS_TRUSTED));
}
-
- setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
- RUNTIME_SCHEMA_TYPE, Set.of(EXECUTE_APP_FUNCTIONS));
- setSchemaRequestBuilder.addRequiredPermissionsForSchemaTypeVisibility(
- RUNTIME_SCHEMA_TYPE, Set.of(EXECUTE_APP_FUNCTIONS_TRUSTED));
return setSchemaRequestBuilder.build();
}
@@ -326,13 +351,17 @@
* This method returns a map of package names to a set of function ids from the AppFunction
* metadata.
*
- * @param schemaType The name space of the AppFunction metadata.
+ * @param searchSession The {@link FutureAppSearchSession} to search the AppFunction metadata.
+ * @param schemaType The schema type of the AppFunction metadata.
+ * @param propertyFunctionId The property name of the function id in the AppFunction metadata.
+ * @param propertyPackageName The property name of the package name in the AppFunction metadata.
* @return A map of package names to a set of function ids from the AppFunction metadata.
*/
@NonNull
@VisibleForTesting
@WorkerThread
- ArrayMap<String, ArraySet<String>> getPackageToFunctionIdMap(
+ static ArrayMap<String, ArraySet<String>> getPackageToFunctionIdMap(
+ @NonNull FutureAppSearchSession searchSession,
@NonNull String schemaType,
@NonNull String propertyFunctionId,
@NonNull String propertyPackageName)
@@ -343,7 +372,7 @@
ArrayMap<String, ArraySet<String>> packageToFunctionIds = new ArrayMap<>();
FutureSearchResults futureSearchResults =
- mFutureAppSearchSession
+ searchSession
.search(
"",
buildMetadataSearchSpec(
@@ -394,13 +423,15 @@
/** Gets the SHA-256 certificate from a {@link PackageManager}, or null if it is not found. */
@Nullable
- private byte[] getCertificate(@NonNull String packageName) {
+ private byte[] getCertificate(
+ @NonNull PackageManager packageManager, @NonNull String packageName) {
+ Objects.requireNonNull(packageManager);
Objects.requireNonNull(packageName);
PackageInfo packageInfo;
try {
packageInfo =
Objects.requireNonNull(
- mPackageManager.getPackageInfo(
+ packageManager.getPackageInfo(
packageName,
PackageManager.GET_META_DATA
| PackageManager.GET_SIGNING_CERTIFICATES));
diff --git a/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncPerUser.java b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncPerUser.java
new file mode 100644
index 0000000..f421527
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/MetadataSyncPerUser.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 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.appfunctions;
+
+import android.annotation.Nullable;
+import android.app.appsearch.AppSearchManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+/** A Singleton class that manages per-user metadata sync adapters. */
+public final class MetadataSyncPerUser {
+ private static final String TAG = MetadataSyncPerUser.class.getSimpleName();
+
+ /** A map of per-user adapter for synchronizing appFunction metadata. */
+ @GuardedBy("sLock")
+ private static final SparseArray<MetadataSyncAdapter> sPerUserMetadataSyncAdapter =
+ new SparseArray<>();
+
+ private static final Object sLock = new Object();
+
+ /**
+ * Returns the per-user metadata sync adapter for the given user.
+ *
+ * @param user The user for which to get the metadata sync adapter.
+ * @param userContext The user context for the given user.
+ * @return The metadata sync adapter for the given user.
+ */
+ @Nullable
+ public static MetadataSyncAdapter getPerUserMetadataSyncAdapter(
+ UserHandle user, Context userContext) {
+ synchronized (sLock) {
+ MetadataSyncAdapter metadataSyncAdapter =
+ sPerUserMetadataSyncAdapter.get(user.getIdentifier(), null);
+ if (metadataSyncAdapter == null) {
+ AppSearchManager perUserAppSearchManager =
+ userContext.getSystemService(AppSearchManager.class);
+ PackageManager perUserPackageManager = userContext.getPackageManager();
+ if (perUserAppSearchManager != null) {
+ metadataSyncAdapter =
+ new MetadataSyncAdapter(
+ AppFunctionExecutors.getPerUserSyncExecutor(user),
+ perUserPackageManager,
+ perUserAppSearchManager);
+ sPerUserMetadataSyncAdapter.put(user.getIdentifier(), metadataSyncAdapter);
+ return metadataSyncAdapter;
+ }
+ }
+ return metadataSyncAdapter;
+ }
+ }
+
+ /**
+ * Removes the per-user metadata sync adapter for the given user.
+ *
+ * @param user The user for which to remove the metadata sync adapter.
+ */
+ public static void removeUserSyncAdapter(UserHandle user) {
+ synchronized (sLock) {
+ sPerUserMetadataSyncAdapter.remove(user.getIdentifier());
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index 2c261fe..bd1b0ea 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -732,6 +732,7 @@
// These autofill id's are being refilled, so they had failed previously.
// Note that these autofillIds correspond to the new autofill ids after relayout.
event.mFailedAutofillIds = new ArraySet<>(autofillIds);
+ setHasRelayoutLog();
});
}
@@ -753,6 +754,7 @@
int failureCount = ids.size();
if (isRefill) {
event.mViewFailedOnRefillCount = failureCount;
+ setHasRelayoutLog();
} else {
event.mViewFillFailureCount = failureCount;
event.mViewFailedPriorToRefillCount = failureCount;
@@ -834,6 +836,19 @@
}
/**
+ * Set the log contains relayout metrics.
+ * This is being added as a temporary measure to add logging.
+ * In future, when we map Session's old view states to the new autofill id's as part of fixing
+ * save for relayout cases, we no longer would need this. But till then, this is needed to set
+ * autofill logs for relayout cases.
+ */
+ private void setHasRelayoutLog() {
+ mEventInternal.ifPresent(event -> {
+ event.mHasRelayoutLog = true;
+ });
+ }
+
+ /**
* Finish and log the event.
*/
public void logAndEndEvent(String caller) {
@@ -844,8 +859,10 @@
}
PresentationStatsEventInternal event = mEventInternal.get();
- boolean ignoreLogging = !event.mIsDatasetAvailable;
-
+ boolean ignoreLogging = !event.mIsDatasetAvailable
+ && !event.mHasRelayoutLog
+ && !(event.mFixExpireResponseDuringAuthCount > 0)
+ && !(event.mNotifyViewEnteredIgnoredDuringAuthCount > 0);
if (sVerbose) {
Slog.v(TAG, "(" + caller + ") "
+ (ignoreLogging ? "IGNORING - following event won't be logged: " : "")
@@ -1032,8 +1049,9 @@
ArraySet<AutofillId> mFailedAutofillIds = new ArraySet<>();
ArraySet<AutofillId> mAlreadyFilledAutofillIds = new ArraySet<>();
- // Not logged - used for internal logic
+ // Following are not logged and used only for internal logic
boolean shouldResetShownCount = false;
+ boolean mHasRelayoutLog = false;
PresentationStatsEventInternal() {}
}
diff --git a/services/autofill/java/com/android/server/autofill/TEST_MAPPING b/services/autofill/java/com/android/server/autofill/TEST_MAPPING
index d8a6917..1dbeebe 100644
--- a/services/autofill/java/com/android/server/autofill/TEST_MAPPING
+++ b/services/autofill/java/com/android/server/autofill/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit-large": [
{
- "name": "CtsAutoFillServiceTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAutoFillServiceTestCases_android_server_autofill_Presubmit"
}
]
}
diff --git a/services/backup/TEST_MAPPING b/services/backup/TEST_MAPPING
index e153230..0c14e56 100644
--- a/services/backup/TEST_MAPPING
+++ b/services/backup/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.backup"
- }
- ]
+ "name": "FrameworksMockingServicesTests_backup"
},
{
"name": "CtsBackupTestCases",
diff --git a/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java b/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
index 1559a3f..df3071e 100644
--- a/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
+++ b/services/companion/java/com/android/server/companion/securechannel/AttestationVerifier.java
@@ -53,9 +53,8 @@
*
* @param remoteAttestation the full certificate chain containing attestation extension.
* @param attestationChallenge attestation challenge for authentication.
- * @return true if attestation is successfully verified; false otherwise.
+ * @return 1 if attestation is successfully verified; 0 otherwise.
*/
- @NonNull
public int verifyAttestation(
@NonNull byte[] remoteAttestation,
@NonNull byte[] attestationChallenge
diff --git a/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING b/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
index caa877c..14579c6 100644
--- a/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
+++ b/services/companion/java/com/android/server/companion/virtual/TEST_MAPPING
@@ -1,81 +1,32 @@
{
"presubmit": [
{
- "name": "CtsVirtualDevicesTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVirtualDevicesTestCases"
},
{
- "name": "CtsVirtualDevicesAudioTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVirtualDevicesAudioTestCases"
},
{
- "name": "CtsVirtualDevicesSensorTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVirtualDevicesSensorTestCases"
},
{
- "name": "CtsVirtualDevicesAppLaunchTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVirtualDevicesAppLaunchTestCases"
},
{
"name": "CtsVirtualDevicesCameraTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
"keywords": ["primary-device"]
},
{
- "name": "CtsHardwareTestCases",
- "options": [
- {
- "include-filter": "android.hardware.input.cts.tests"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ],
+ "name": "CtsHardwareTestCases_cts_tests",
"file_patterns": ["Virtual[^/]*\\.java"]
},
{
- "name": "CtsAccessibilityServiceTestCases",
- "options": [
- {
- "include-filter": "android.accessibilityservice.cts.AccessibilityDisplayProxyTest"
- },
- {
- "exclude-annotation": "android.support.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAccessibilityServiceTestCases_cts_accessibilitydisplayproxytest"
}
],
"postsubmit": [
{
- "name": "CtsMediaAudioTestCases",
- "options": [
- {
- "include-filter": "android.media.audio.cts.AudioFocusWithVdmTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsMediaAudioTestCases_cts_audiofocuswithvdmtest"
},
{
"name": "CtsPermissionTestCases",
@@ -92,12 +43,7 @@
]
},
{
- "name": "CtsPermissionMultiDeviceTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsPermissionMultiDeviceTestCases"
}
]
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1b5b7e8..4e36e3f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -237,6 +237,7 @@
"dreams_flags_lib",
"aconfig_new_storage_flags_lib",
"powerstats_flags_lib",
+ "locksettings_flags_lib",
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 30f3fd2..68d0ad2 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -1,13 +1,7 @@
{
"presubmit": [
{
- "name": "CtsLocationFineTestCases",
- "options": [
- {
- // TODO: Wait for test to deflake - b/293934372
- "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
- }
- ]
+ "name": "CtsLocationFineTestCases_android_server_location"
},
{
"name": "CtsLocationCoarseTestCases"
@@ -20,12 +14,7 @@
"file_patterns": ["NotificationManagerService\\.java"]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.ToastWindowTest"
- }
- ],
+ "name": "CtsWindowManagerDeviceWindow_window_toastwindowtest",
"file_patterns": ["NotificationManagerService\\.java"]
},
{
@@ -103,12 +92,7 @@
"file_patterns": ["VcnManagementService\\.java"]
},
{
- "name": "FrameworksVpnTests",
- "options": [
- {
- "exclude-annotation": "com.android.testutils.SkipPresubmit"
- }
- ],
+ "name": "FrameworksVpnTests_android_server_connectivity",
"file_patterns": ["VpnManagerService\\.java"]
},
{
@@ -123,6 +107,15 @@
"Background.*\\.java",
"Activity.*\\.java"
]
+ },
+ {
+ "name": "CtsOsTestCases",
+ "file_patterns": ["StorageManagerService\\.java"],
+ "options": [
+ {
+ "include-filter": "android.os.storage.cts.StorageManagerTest"
+ }
+ ]
}
],
"presubmit-large": [
@@ -180,15 +173,6 @@
"include-filter": "com.android.server.wm.BackgroundActivityStart*"
}
]
- },
- {
- "name": "CtsOsTestCases",
- "file_patterns": ["StorageManagerService\\.java"],
- "options": [
- {
- "include-filter": "android.os.storage.cts.StorageManagerTest"
- }
- ]
}
]
}
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index e2b6bd6..d19899f 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -489,7 +489,10 @@
// Check subscription is active first; much cheaper/faster check, and an app (currently)
// cannot be carrier privileged for inactive subscriptions.
- if (subMgr.isValidSlotIndex(info.getSimSlotIndex())
+ final int simSlotIndex = info.getSimSlotIndex();
+ final boolean isValidSlotIndex =
+ simSlotIndex >= 0 && simSlotIndex < telMgr.getActiveModemCount();
+ if (isValidSlotIndex
&& telMgr.checkCarrierPrivilegesForPackage(pkgName)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
// TODO (b/173717728): Allow configuration for inactive, but manageable
diff --git a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
index 4da5cfc..9398c7a 100644
--- a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
+++ b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java
@@ -34,7 +34,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import android.util.Slog;
@@ -73,7 +72,6 @@
private final LockSettingsInternal mLockSettings;
private final BiometricManager mBiometricManager;
private final KeyguardManager mKeyguardManager;
- private final PowerManager mPowerManager;
private final WindowManagerInternal mWindowManager;
private final UserManagerInternal mUserManager;
@VisibleForTesting
@@ -93,7 +91,6 @@
mBiometricManager = Objects.requireNonNull(
context.getSystemService(BiometricManager.class));
mKeyguardManager = Objects.requireNonNull(context.getSystemService(KeyguardManager.class));
- mPowerManager = Objects.requireNonNull(context.getSystemService(PowerManager.class));
mWindowManager = Objects.requireNonNull(
LocalServices.getService(WindowManagerInternal.class));
mUserManager = Objects.requireNonNull(LocalServices.getService(UserManagerInternal.class));
@@ -290,9 +287,6 @@
parentUserId);
}
- // Power off the display
- mPowerManager.goToSleep(SystemClock.uptimeMillis());
-
// Lock the device
mWindowManager.lockNow();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3c57476..54a7410 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4772,7 +4772,7 @@
if (!mConstants.mEnableWaitForFinishAttachApplication) {
finishAttachApplicationInner(startSeq, callingUid, pid);
}
- maybeSendBootCompletedLocked(app);
+ maybeSendBootCompletedLocked(app, isRestrictedBackupMode);
} catch (Exception e) {
// We need kill the process group here. (b/148588589)
Slog.wtf(TAG, "Exception thrown during bind of " + app, e);
@@ -5017,7 +5017,7 @@
* Send LOCKED_BOOT_COMPLETED and BOOT_COMPLETED to the package explicitly when unstopped,
* or when the package first starts in private space
*/
- private void maybeSendBootCompletedLocked(ProcessRecord app) {
+ private void maybeSendBootCompletedLocked(ProcessRecord app, boolean isRestrictedBackupMode) {
boolean sendBroadcast = false;
if (android.os.Flags.allowPrivateProfile()
&& android.multiuser.Flags.enablePrivateSpaceFeatures()) {
@@ -5043,6 +5043,9 @@
RESTRICTION_REASON_USAGE, "unknown", RESTRICTION_SOURCE_USER, 0L);
}
+ // Don't send BOOT_COMPLETED if currently in restricted backup mode
+ if (isRestrictedBackupMode) return;
+
if (!sendBroadcast) {
if (!android.content.pm.Flags.stayStopped()) return;
// Nothing to do if it wasn't previously stopped
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2416ab6..75e9fad 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1833,7 +1833,7 @@
@Override
@EnforcePermission(UPDATE_DEVICE_STATS)
- public void noteScreenState(final int state) {
+ public void noteScreenState(final int displayId, final int state, final int reason) {
super.noteScreenState_enforcePermission();
synchronized (mLock) {
@@ -1843,7 +1843,8 @@
mHandler.post(() -> {
if (DBG) Slog.d(TAG, "begin noteScreenState");
synchronized (mStats) {
- mStats.noteScreenStateLocked(0, state, elapsedRealtime, uptime, currentTime);
+ mStats.noteScreenStateLocked(
+ displayId, state, reason, elapsedRealtime, uptime, currentTime);
}
if (DBG) Slog.d(TAG, "end noteScreenState");
});
@@ -1853,7 +1854,7 @@
@Override
@EnforcePermission(UPDATE_DEVICE_STATS)
- public void noteScreenBrightness(final int brightness) {
+ public void noteScreenBrightness(final int displayId, final int brightness) {
super.noteScreenBrightness_enforcePermission();
synchronized (mLock) {
@@ -1861,7 +1862,8 @@
final long uptime = SystemClock.uptimeMillis();
mHandler.post(() -> {
synchronized (mStats) {
- mStats.noteScreenBrightnessLocked(0, brightness, elapsedRealtime, uptime);
+ mStats.noteScreenBrightnessLocked(
+ displayId, brightness, elapsedRealtime, uptime);
}
});
}
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index ab5e2d0..6383dcb 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -22,32 +22,10 @@
]
},
{
- "name": "CtsAppFgsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAppFgsTestCases_pm_Presubmit"
},
{
- "name": "CtsShortFgsTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsShortFgsTestCases_pm_Presubmit"
},
{
"name": "FrameworksServicesTests_android_server_am_Presubmit"
@@ -73,23 +51,14 @@
},
{
"file_patterns": ["Broadcast.*"],
- "name": "CtsBroadcastTestCases",
- "options": [
- { "exclude-annotation": "androidx.test.filters.LargeTest" },
- { "exclude-annotation": "androidx.test.filters.FlakyTest" },
- { "exclude-annotation": "org.junit.Ignore" }
- ]
+ "name": "CtsBroadcastTestCases_android_server_am"
},
{
- "name": "CtsBRSTestCases",
"file_patterns": [
"ActivityManagerService\\.java",
"BroadcastQueue\\.java"
],
- "options": [
- { "exclude-annotation": "androidx.test.filters.FlakyTest" },
- { "exclude-annotation": "org.junit.Ignore" }
- ]
+ "name": "CtsBRSTestCases"
}
],
"postsubmit": [
@@ -110,13 +79,7 @@
]
},
{
- "name": "CtsStatsdAtomHostTestCases",
- "options": [
- { "include-filter": "android.cts.statsdatom.appexit.AppExitHostTest" },
- { "exclude-annotation": "androidx.test.filters.LargeTest" },
- { "exclude-annotation": "androidx.test.filters.FlakyTest" },
- { "exclude-annotation": "org.junit.Ignore" }
- ]
+ "name": "CtsStatsdAtomHostTestCases_appexit_appexithosttest"
},
{
"name": "CtsContentTestCases",
diff --git a/services/core/java/com/android/server/app/TEST_MAPPING b/services/core/java/com/android/server/app/TEST_MAPPING
index b718ce6..9e76175 100644
--- a/services/core/java/com/android/server/app/TEST_MAPPING
+++ b/services/core/java/com/android/server/app/TEST_MAPPING
@@ -1,26 +1,10 @@
{
"presubmit": [
{
- "name": "CtsGameManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsGameManagerTestCases"
},
{
- "name": "CtsStatsdAtomHostTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.cts.statsdatom.gamemanager"
- }
- ],
+ "name": "CtsStatsdAtomHostTestCases_statsdatom_gamemanager",
"file_patterns": [
"(/|^)GameManagerService.java"
]
@@ -29,18 +13,7 @@
"name": "FrameworksMockingServicesTests_android_server_app"
},
{
- "name": "FrameworksCoreGameManagerTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.app"
- }
- ],
+ "name": "FrameworksCoreGameManagerTests_android_app",
"file_patterns": [
"(/|^)GameManagerService.java", "(/|^)GameManagerSettings.java"
]
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index 9317c1e..25dd30b 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsAppOpsTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAppOpsTestCases"
},
{
"name": "CtsAppOps2TestCases"
@@ -21,12 +16,7 @@
"name": "CtsPermissionTestCases_Platform"
},
{
- "name": "CtsAppTestCases",
- "options": [
- {
- "include-filter": "android.app.cts.ActivityManagerApi29Test"
- }
- ]
+ "name": "CtsAppTestCases_cts_activitymanagerapi29test"
},
{
"name": "CtsStatsdAtomHostTestCases",
diff --git a/services/core/java/com/android/server/attention/TEST_MAPPING b/services/core/java/com/android/server/attention/TEST_MAPPING
index e5b0344..519ed07 100644
--- a/services/core/java/com/android/server/attention/TEST_MAPPING
+++ b/services/core/java/com/android/server/attention/TEST_MAPPING
@@ -1,24 +1,7 @@
{
"presubmit": [
{
- "name": "CtsVoiceInteractionTestCases",
- "options": [
- {
- "include-filter": "android.voiceinteraction.cts.AlwaysOnHotwordDetectorTest"
- },
- {
- "include-filter": "android.voiceinteraction.cts.unittests.HotwordDetectedResultTest"
- },
- {
- "include-filter": "android.voiceinteraction.cts.HotwordDetectionServiceBasicTest"
- },
- {
- "include-filter": "android.voiceinteraction.cts.HotwordDetectionServiceProximityTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVoiceInteractionTestCases_android_server_attention"
}
]
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 1cf9935..55d9c6e 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -533,7 +533,8 @@
AudioDeviceInfo.TYPE_BLE_SPEAKER,
AudioDeviceInfo.TYPE_LINE_ANALOG,
AudioDeviceInfo.TYPE_HDMI,
- AudioDeviceInfo.TYPE_AUX_LINE
+ AudioDeviceInfo.TYPE_AUX_LINE,
+ AudioDeviceInfo.TYPE_BUS
};
/*package */ static boolean isValidCommunicationDevice(@NonNull AudioDeviceInfo device) {
@@ -541,7 +542,8 @@
return device.isSink() && isValidCommunicationDeviceType(device.getType());
}
- private static boolean isValidCommunicationDeviceType(int deviceType) {
+ private static boolean isValidCommunicationDeviceType(
+ @AudioDeviceInfo.AudioDeviceType int deviceType) {
for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
if (deviceType == type) {
return true;
@@ -740,7 +742,8 @@
* @param deviceType the device type the query applies to.
* @return true if this device type is requested for communication.
*/
- private boolean isDeviceRequestedForCommunication(int deviceType) {
+ private boolean isDeviceRequestedForCommunication(
+ @AudioDeviceInfo.AudioDeviceType int deviceType) {
synchronized (mDeviceStateLock) {
AudioDeviceAttributes device = requestedCommunicationDevice();
return device != null && device.getType() == deviceType;
@@ -754,7 +757,8 @@
* @param deviceType the device type the query applies to.
* @return true if this device type is requested for communication.
*/
- private boolean isDeviceOnForCommunication(int deviceType) {
+ private boolean isDeviceOnForCommunication(
+ @AudioDeviceInfo.AudioDeviceType int deviceType) {
synchronized (mDeviceStateLock) {
AudioDeviceAttributes device = preferredCommunicationDevice();
return device != null && device.getType() == deviceType;
@@ -768,7 +772,8 @@
* @param deviceType the device type the query applies to.
* @return true if this device type is requested for communication.
*/
- private boolean isDeviceActiveForCommunication(int deviceType) {
+ private boolean isDeviceActiveForCommunication(
+ @AudioDeviceInfo.AudioDeviceType int deviceType) {
return mActiveCommunicationDevice != null
&& mActiveCommunicationDevice.getType() == deviceType
&& mPreferredCommunicationDevice != null
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c3d09bb..99404428 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4006,6 +4006,7 @@
&& isFullVolumeDevice(device);
boolean tvConditions = mHdmiTvClient != null
&& mHdmiSystemAudioSupported
+ && isFullVolumeDevice(device)
&& !isAbsoluteVolumeDevice(device)
&& !isA2dpAbsoluteVolumeDevice(device);
diff --git a/services/core/java/com/android/server/cpu/CpuInfoReader.java b/services/core/java/com/android/server/cpu/CpuInfoReader.java
index 984ad1d..a68451a 100644
--- a/services/core/java/com/android/server/cpu/CpuInfoReader.java
+++ b/services/core/java/com/android/server/cpu/CpuInfoReader.java
@@ -40,6 +40,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -80,13 +81,14 @@
/** package **/ @interface CpusetCategory{}
// TODO(b/242722241): Protect updatable variables with a local lock.
- private final File mCpusetDir;
private final long mMinReadIntervalMillis;
private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray();
private final SparseArray<File> mCpuFreqPolicyDirsById = new SparseArray<>();
private final SparseArray<StaticPolicyInfo> mStaticPolicyInfoById = new SparseArray<>();
private final SparseArray<LongSparseLongArray> mTimeInStateByPolicyId = new SparseArray<>();
+ private final AtomicBoolean mShouldReadCpusetCategories;
+ private File mCpusetDir;
private File mCpuFreqDir;
private File mProcStatFile;
private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>();
@@ -106,10 +108,13 @@
mCpuFreqDir = cpuFreqDir;
mProcStatFile = procStatFile;
mMinReadIntervalMillis = minReadIntervalMillis;
+ mShouldReadCpusetCategories = new AtomicBoolean(true);
}
/**
* Initializes CpuInfoReader and returns a boolean to indicate whether the reader is enabled.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
public boolean init() {
if (mCpuFreqPolicyDirsById.size() > 0) {
@@ -139,8 +144,7 @@
Slogf.e(TAG, "Missing proc stat file at %s", mProcStatFile.getAbsolutePath());
return false;
}
- readCpusetCategories();
- if (mCpusetCategoriesByCpus.size() == 0) {
+ if (!readCpusetCategories()) {
Slogf.e(TAG, "Failed to read cpuset information from %s", mCpusetDir.getAbsolutePath());
return false;
}
@@ -163,10 +167,19 @@
return true;
}
+ public void stopPeriodicCpusetReading() {
+ mShouldReadCpusetCategories.set(false);
+ if (!readCpusetCategories()) {
+ Slogf.e(TAG, "Failed to read cpuset information from %s",
+ mCpusetDir.getAbsolutePath());
+ mIsEnabled = false;
+ }
+ }
+
/**
* Reads CPU information from proc and sys fs files exposed by the Kernel.
*
- * @return SparseArray keyed by CPU core ID; {@code null} on error or when disabled.
+ * <p>Returns SparseArray keyed by CPU core ID; {@code null} on error or when disabled.
*/
@Nullable
public SparseArray<CpuInfo> readCpuInfos() {
@@ -183,6 +196,12 @@
}
mLastReadUptimeMillis = uptimeMillis;
mLastReadCpuInfos = null;
+ if (mShouldReadCpusetCategories.get() && !readCpusetCategories()) {
+ Slogf.e(TAG, "Failed to read cpuset information from %s",
+ mCpusetDir.getAbsolutePath());
+ mIsEnabled = false;
+ return null;
+ }
SparseArray<CpuUsageStats> cpuUsageStatsByCpus = readLatestCpuUsageStats();
if (cpuUsageStatsByCpus == null || cpuUsageStatsByCpus.size() == 0) {
Slogf.e(TAG, "Failed to read latest CPU usage stats");
@@ -324,7 +343,7 @@
/**
* Sets the CPU frequency for testing.
*
- * <p>Return {@code true} on success. Otherwise, returns {@code false}.
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
@VisibleForTesting
boolean setCpuFreqDir(File cpuFreqDir) {
@@ -354,7 +373,7 @@
/**
* Sets the proc stat file for testing.
*
- * <p>Return true on success. Otherwise, returns false.
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
@VisibleForTesting
boolean setProcStatFile(File procStatFile) {
@@ -366,6 +385,21 @@
return true;
}
+ /**
+ * Set the cpuset directory for testing.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
+ */
+ @VisibleForTesting
+ boolean setCpusetDir(File cpusetDir) {
+ if (!cpusetDir.exists() && !cpusetDir.isDirectory()) {
+ Slogf.e(TAG, "Missing or invalid cpuset directory at %s", cpusetDir.getAbsolutePath());
+ return false;
+ }
+ mCpusetDir = cpusetDir;
+ return true;
+ }
+
private void populateCpuFreqPolicyDirsById(File[] policyDirs) {
mCpuFreqPolicyDirsById.clear();
for (int i = 0; i < policyDirs.length; i++) {
@@ -381,12 +415,27 @@
}
}
- private void readCpusetCategories() {
+ /**
+ * Reads cpuset categories by CPU.
+ *
+ * <p>The cpusets are read from the cpuset category specific directories
+ * under the /dev/cpuset directory. The cpuset categories are subject to change at any point
+ * during system bootup, as determined by the init rules specified within the init.rc files.
+ * Therefore, it's necessary to read the cpuset categories each time before accessing CPU usage
+ * statistics until the system boot completes. Once the boot is complete, the latest changes to
+ * the cpuset categories will take a few seconds to propagate. Thus, on boot complete,
+ * the periodic reading is stopped with a delay of
+ * {@link CpuMonitorService#STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS}.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
+ */
+ private boolean readCpusetCategories() {
File[] cpusetDirs = mCpusetDir.listFiles(File::isDirectory);
if (cpusetDirs == null) {
Slogf.e(TAG, "Missing cpuset directories at %s", mCpusetDir.getAbsolutePath());
- return;
+ return false;
}
+ mCpusetCategoriesByCpus.clear();
for (int i = 0; i < cpusetDirs.length; i++) {
File dir = cpusetDirs[i];
@CpusetCategory int cpusetCategory;
@@ -418,6 +467,7 @@
}
}
}
+ return mCpusetCategoriesByCpus.size() > 0;
}
private void readStaticPolicyInfo() {
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java
index 7ea2c1b..88ff7e4 100644
--- a/services/core/java/com/android/server/cpu/CpuMonitorService.java
+++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java
@@ -22,6 +22,7 @@
import static com.android.server.cpu.CpuAvailabilityMonitoringConfig.CPUSET_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP;
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import android.annotation.Nullable;
import android.content.Context;
@@ -82,6 +83,15 @@
// frequently. Should this duration be increased as well when this happens?
private static final long LATEST_AVAILABILITY_DURATION_MILLISECONDS =
TimeUnit.SECONDS.toMillis(30);
+ /**
+ * Delay to stop the periodic cpuset reading after boot complete.
+ *
+ * Device specific implementations can update cpuset on boot complete. This may take
+ * a few seconds to propagate. So, wait for a few minutes before stopping the periodic cpuset
+ * reading.
+ */
+ private static final long STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS =
+ TimeUnit.MINUTES.toMillis(2);
private final Context mContext;
private final HandlerThread mHandlerThread;
@@ -90,6 +100,7 @@
private final long mNormalMonitoringIntervalMillis;
private final long mDebugMonitoringIntervalMillis;
private final long mLatestAvailabilityDurationMillis;
+ private final long mStopPeriodicCpusetReadingDelayMillis;
private final Object mLock = new Object();
@GuardedBy("mLock")
private final SparseArrayMap<CpuMonitorInternal.CpuAvailabilityCallback,
@@ -153,13 +164,15 @@
this(context, new CpuInfoReader(), new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, /* allowIo= */ true),
Build.IS_USERDEBUG || Build.IS_ENG, NORMAL_MONITORING_INTERVAL_MILLISECONDS,
- DEBUG_MONITORING_INTERVAL_MILLISECONDS, LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ DEBUG_MONITORING_INTERVAL_MILLISECONDS, LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
}
@VisibleForTesting
CpuMonitorService(Context context, CpuInfoReader cpuInfoReader, HandlerThread handlerThread,
boolean shouldDebugMonitor, long normalMonitoringIntervalMillis,
- long debugMonitoringIntervalMillis, long latestAvailabilityDurationMillis) {
+ long debugMonitoringIntervalMillis, long latestAvailabilityDurationMillis,
+ long stopPeriodicCpusetReadingDelayMillis) {
super(context);
mContext = context;
mHandlerThread = handlerThread;
@@ -167,6 +180,7 @@
mNormalMonitoringIntervalMillis = normalMonitoringIntervalMillis;
mDebugMonitoringIntervalMillis = debugMonitoringIntervalMillis;
mLatestAvailabilityDurationMillis = latestAvailabilityDurationMillis;
+ mStopPeriodicCpusetReadingDelayMillis = stopPeriodicCpusetReadingDelayMillis;
mCpuInfoReader = cpuInfoReader;
mCpusetInfosByCpuset = new SparseArray<>(2);
mCpusetInfosByCpuset.append(CPUSET_ALL, new CpusetInfo(CPUSET_ALL));
@@ -200,6 +214,16 @@
}
}
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase != PHASE_BOOT_COMPLETED) {
+ return;
+ }
+ Slogf.i(TAG, "Stopping periodic cpuset reading on boot complete");
+ mHandler.postDelayed(() -> mCpuInfoReader.stopPeriodicCpusetReading(),
+ mStopPeriodicCpusetReadingDelayMillis);
+ }
+
@VisibleForTesting
long getCurrentMonitoringIntervalMillis() {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/crashrecovery/TEST_MAPPING b/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
index 615db34..537fb325 100644
--- a/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
+++ b/services/core/java/com/android/server/crashrecovery/TEST_MAPPING
@@ -1,4 +1,9 @@
{
+ "presubmit": [
+ {
+ "name": "CrashRecoveryModuleTests"
+ }
+ ],
"postsubmit": [
{
"name": "FrameworksMockingServicesTests",
@@ -7,9 +12,6 @@
"include-filter": "com.android.server.RescuePartyTest"
}
]
- },
- {
- "name": "CrashRecoveryModuleTests"
}
]
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index c3faec0..04573f4 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -536,7 +536,9 @@
mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
- if (mDisplayId == Display.DEFAULT_DISPLAY) {
+ if (flags.isBatteryStatsEnabledForAllDisplays()) {
+ mBatteryStats = BatteryStatsService.getService();
+ } else if (mDisplayId == Display.DEFAULT_DISPLAY) {
mBatteryStats = BatteryStatsService.getService();
} else {
mBatteryStats = null;
@@ -2791,8 +2793,7 @@
screenState, mDisplayStatsId, reason);
if (mBatteryStats != null) {
try {
- // TODO(multi-display): make this multi-display
- mBatteryStats.noteScreenState(screenState);
+ mBatteryStats.noteScreenState(mDisplayId, screenState, reason);
} catch (RemoteException e) {
// same process
}
@@ -2807,7 +2808,7 @@
int brightnessInt = mFlags.isBrightnessIntRangeUserPerceptionEnabled()
? BrightnessSynchronizer.brightnessFloatToIntSetting(mContext, brightness)
: BrightnessSynchronizer.brightnessFloatToInt(brightness);
- mBatteryStats.noteScreenBrightness(brightnessInt);
+ mBatteryStats.noteScreenBrightness(mDisplayId, brightnessInt);
} catch (RemoteException e) {
// same process
}
diff --git a/services/core/java/com/android/server/display/TEST_MAPPING b/services/core/java/com/android/server/display/TEST_MAPPING
index 049b2fd..4d7962f 100644
--- a/services/core/java/com/android/server/display/TEST_MAPPING
+++ b/services/core/java/com/android/server/display/TEST_MAPPING
@@ -1,21 +1,12 @@
{
"presubmit": [
{
- "name": "DisplayServiceTests",
- "options": [
- {"include-filter": "com.android.server.display"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "DisplayServiceTests_server_display"
}
],
"postsubmit": [
{
- "name": "DisplayServiceTests",
- "options": [
- {"include-filter": "com.android.server.display"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "DisplayServiceTests_server_display"
}
]
}
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 69b67c8..f600e7f 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -200,6 +200,11 @@
Flags::normalBrightnessForDozeParameter
);
+ private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState(
+ Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS,
+ Flags::enableBatteryStatsForAllDisplays
+ );
+
/**
* @return {@code true} if 'port' is allowed in display layout configuration file.
*/
@@ -415,6 +420,14 @@
}
/**
+ * @return {@code true} if battery stats is enabled for all displays, not just the primary
+ * display.
+ */
+ public boolean isBatteryStatsEnabledForAllDisplays() {
+ return mEnableBatteryStatsForAllDisplays.isEnabled();
+ }
+
+ /**
* dumps all flagstates
* @param pw printWriter
*/
@@ -456,6 +469,7 @@
pw.println(" " + mNewHdrBrightnessModifier);
pw.println(" " + mNormalBrightnessForDozeParameter);
pw.println(" " + mIdleScreenConfigInSubscribingLightSensor);
+ pw.println(" " + mEnableBatteryStatsForAllDisplays);
}
private static class FlagState {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 70230b4..9968ba5 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -349,3 +349,11 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_battery_stats_for_all_displays"
+ namespace: "display_manager"
+ description: "Flag to enable battery stats for all displays."
+ bug: "366112793"
+ is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 5db17bb..d0ad6fc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -171,6 +171,17 @@
addAndStartAction(
new HotplugDetectionAction(HdmiCecLocalDevicePlayback.this));
}
+
+ if (mService.isHdmiControlEnhancedBehaviorFlagEnabled()) {
+ List<PowerStatusMonitorActionFromPlayback>
+ powerStatusMonitorActionsFromPlayback =
+ getActions(PowerStatusMonitorActionFromPlayback.class);
+ if (powerStatusMonitorActionsFromPlayback.isEmpty()) {
+ addAndStartAction(
+ new PowerStatusMonitorActionFromPlayback(
+ HdmiCecLocalDevicePlayback.this));
+ }
+ }
}
});
addAndStartAction(action);
@@ -686,6 +697,7 @@
removeAction(DeviceDiscoveryAction.class);
removeAction(HotplugDetectionAction.class);
removeAction(NewDeviceAction.class);
+ removeAction(PowerStatusMonitorActionFromPlayback.class);
super.disableDevice(initiatedByCec, callback);
clearDeviceInfoList();
checkIfPendingActionsCleared();
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 271836a..ac75ef7 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -16,6 +16,8 @@
package com.android.server.hdmi;
+import static android.media.tv.flags.Flags.hdmiControlEnhancedBehavior;
+
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
import static android.hardware.hdmi.HdmiControlManager.EARC_FEATURE_DISABLED;
@@ -1378,7 +1380,8 @@
@ServiceThreadOnly
private List<Integer> getCecLocalDeviceTypes() {
ArrayList<Integer> allLocalDeviceTypes = new ArrayList<>(mCecLocalDevices);
- if (isDsmEnabled() && !allLocalDeviceTypes.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)
+ if (!isTvDevice() && isDsmEnabled()
+ && !allLocalDeviceTypes.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)
&& isArcSupported() && mSoundbarModeFeatureFlagEnabled) {
allLocalDeviceTypes.add(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
}
@@ -5137,4 +5140,8 @@
tv().startArcAction(enabled, callback);
}
}
+
+ protected boolean isHdmiControlEnhancedBehaviorFlagEnabled() {
+ return hdmiControlEnhancedBehavior();
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/PowerStatusMonitorActionFromPlayback.java b/services/core/java/com/android/server/hdmi/PowerStatusMonitorActionFromPlayback.java
new file mode 100644
index 0000000..9a3cde1
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/PowerStatusMonitorActionFromPlayback.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 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.hdmi;
+
+import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_STANDBY;
+
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * This action is used by playback devices to query TV's power status such that they can go to
+ * standby when the TV reports power off.
+ */
+public class PowerStatusMonitorActionFromPlayback extends HdmiCecFeatureAction {
+ private static final String TAG = "PowerStatusMonitorActionFromPlayback";
+
+ // State that waits for <Report Power Status> once sending <Give Device Power Status>
+ // to all external devices.
+ private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1;
+ // State that waits for next monitoring.
+ private static final int STATE_WAIT_FOR_NEXT_MONITORING = 2;
+ // Monitoring interval (60s)
+ @VisibleForTesting
+ protected static final int MONITORING_INTERVAL_MS = 60000;
+ // Timeout once sending <Give Device Power Status>
+ private static final int REPORT_POWER_STATUS_TIMEOUT_MS = 5000;
+ // Maximum number of retries in case the <Give Device Power Status> failed being sent or times
+ // out.
+ private static final int GIVE_POWER_STATUS_FOR_SOURCE_RETRIES = 5;
+ private int mPowerStatusRetries = 0;
+
+ PowerStatusMonitorActionFromPlayback(HdmiCecLocalDevice source) {
+ super(source);
+ }
+
+ @Override
+ boolean start() {
+ // Start after timeout since the device just finished allocation.
+ mState = STATE_WAIT_FOR_NEXT_MONITORING;
+ addTimer(mState, MONITORING_INTERVAL_MS);
+ return true;
+ }
+
+ @Override
+ boolean processCommand(HdmiCecMessage cmd) {
+ if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS
+ && cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS
+ && cmd.getSource() == Constants.ADDR_TV) {
+ return handleReportPowerStatusFromTv(cmd);
+ }
+ return false;
+ }
+
+ private boolean handleReportPowerStatusFromTv(HdmiCecMessage cmd) {
+ int powerStatus = cmd.getParams()[0] & 0xFF;
+ if (powerStatus == POWER_STATUS_STANDBY) {
+ Slog.d(TAG, "TV reported it turned off, going to sleep.");
+ source().getService().standby();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ void handleTimerEvent(int state) {
+ switch (mState) {
+ case STATE_WAIT_FOR_NEXT_MONITORING:
+ mPowerStatusRetries = 0;
+ queryPowerStatus();
+ break;
+ case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+ handleTimeout();
+ break;
+ }
+ }
+
+ private void queryPowerStatus() {
+ sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(),
+ Constants.ADDR_TV));
+
+ mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
+ addTimer(mState, REPORT_POWER_STATUS_TIMEOUT_MS);
+ }
+
+ private void handleTimeout() {
+ if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS) {
+ if (mPowerStatusRetries++ < GIVE_POWER_STATUS_FOR_SOURCE_RETRIES) {
+ queryPowerStatus();
+ } else {
+ mPowerStatusRetries = 0;
+ mState = STATE_WAIT_FOR_NEXT_MONITORING;
+ addTimer(mState, MONITORING_INTERVAL_MS);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/TEST_MAPPING b/services/core/java/com/android/server/hdmi/TEST_MAPPING
index d116087d..bacacaf 100644
--- a/services/core/java/com/android/server/hdmi/TEST_MAPPING
+++ b/services/core/java/com/android/server/hdmi/TEST_MAPPING
@@ -12,18 +12,7 @@
// Postsubmit tests for TV devices
"tv-postsubmit": [
{
- "name": "HdmiCecTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.hardware.hdmi"
- }
- ],
+ "name": "HdmiCecTests_hardware_hdmi",
"file_patterns": [
"(/|^)DeviceFeature[^/]*", "(/|^)Hdmi[^/]*"
]
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index ca8ae6e..edc35e5 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -16,11 +16,15 @@
package com.android.server.input;
+import static android.Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW;
+import static android.content.PermissionChecker.PERMISSION_GRANTED;
+import static android.content.PermissionChecker.PID_UNKNOWN;
import static android.provider.DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT;
import static android.view.KeyEvent.KEYCODE_UNKNOWN;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.hardware.input.Flags.touchpadVisualizer;
+import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
import android.Manifest;
import android.annotation.EnforcePermission;
@@ -36,6 +40,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.graphics.PixelFormat;
@@ -120,6 +125,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
import com.android.internal.os.SomeArgs;
+import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.DisplayThread;
@@ -129,6 +135,7 @@
import com.android.server.input.debug.FocusEventDebugView;
import com.android.server.input.debug.TouchpadDebugViewController;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.WindowManagerInternal;
import libcore.io.IoUtils;
@@ -176,6 +183,7 @@
private final InputManagerHandler mHandler;
private DisplayManagerInternal mDisplayManagerInternal;
+ private WindowManagerInternal mWindowManagerInternal;
private PackageManagerInternal mPackageManagerInternal;
private final File mDoubleTouchGestureEnableFile;
@@ -547,6 +555,7 @@
}
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+ mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mSettingsObserver.registerAndUpdate();
@@ -2116,6 +2125,7 @@
mKeyboardBacklightController.dump(ipw);
mKeyboardLedController.dump(ipw);
mKeyboardGlyphManager.dump(ipw);
+ mKeyGestureController.dump(ipw);
}
private void dumpAssociations(IndentingPrintWriter pw) {
@@ -2276,6 +2286,14 @@
// Native callback.
@SuppressWarnings("unused")
+ private void notifyTouchpadGestureInfo(int type, int deviceId) {
+ if (mTouchpadDebugViewController != null) {
+ mTouchpadDebugViewController.updateTouchpadGestureInfo(type, deviceId);
+ }
+ }
+
+ // Native callback.
+ @SuppressWarnings("unused")
private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
if (DEBUG) {
Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
@@ -2457,13 +2475,33 @@
// Native callback.
@SuppressWarnings("unused")
- private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
- // TODO(b/358569822): Move shortcut trigger logic from PWM to KeyGestureController
- long value = mKeyGestureController.interceptKeyBeforeDispatching(focus, event, policyFlags);
- if (value != 0) { // If key is consumed (i.e. non-zero value)
- return value;
+ @VisibleForTesting
+ long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
+ final long keyNotConsumed = 0;
+ long value = keyNotConsumed;
+ // TODO(b/358569822) Remove below once we have nicer API for listening to shortcuts
+ if ((event.isMetaPressed() || KeyEvent.isMetaKey(event.getKeyCode()))
+ && shouldInterceptShortcuts(focus)) {
+ return keyNotConsumed;
}
- return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
+ if (useKeyGestureEventHandler()) {
+ value = mKeyGestureController.interceptKeyBeforeDispatching(focus, event, policyFlags);
+ }
+ if (value == keyNotConsumed) {
+ value = mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event,
+ policyFlags);
+ }
+ return value;
+ }
+
+ private boolean shouldInterceptShortcuts(IBinder focusedToken) {
+ KeyInterceptionInfo info =
+ mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken);
+ boolean hasInterceptWindowFlag = info != null && (info.layoutParamsPrivateFlags
+ & WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) != 0;
+ return hasInterceptWindowFlag && PermissionChecker.checkPermissionForDataDelivery(mContext,
+ OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW, PID_UNKNOWN, info.windowOwnerUid,
+ null, null, null) == PERMISSION_GRANTED;
}
// Native callback.
@@ -2748,12 +2786,14 @@
private void enforceManageKeyGesturePermission() {
// TODO(b/361567988): Use @EnforcePermission to enforce permission once flag guarding the
// permission is rolled out
- String systemUIPackage = mContext.getString(R.string.config_systemUi);
- int systemUIAppId = UserHandle.getAppId(mPackageManagerInternal
- .getPackageUid(systemUIPackage, PackageManager.MATCH_SYSTEM_ONLY,
- UserHandle.USER_SYSTEM));
- if (UserHandle.getCallingAppId() == systemUIAppId) {
- return;
+ if (mSystemReady) {
+ String systemUIPackage = mContext.getString(R.string.config_systemUi);
+ int systemUIAppId = UserHandle.getAppId(mPackageManagerInternal
+ .getPackageUid(systemUIPackage, PackageManager.MATCH_SYSTEM_ONLY,
+ UserHandle.USER_SYSTEM));
+ if (UserHandle.getCallingAppId() == systemUIAppId) {
+ return;
+ }
}
if (mContext.checkCallingOrSelfPermission(
Manifest.permission.MANAGE_KEY_GESTURES) == PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index bfdb1c1..7fe7891 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -16,10 +16,15 @@
package com.android.server.input;
+import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
+
import android.annotation.BinderThread;
import android.annotation.MainThread;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.content.Context;
+import android.content.res.Resources;
+
import android.hardware.input.AidlKeyGestureEvent;
import android.hardware.input.IKeyGestureEventListener;
import android.hardware.input.IKeyGestureHandler;
@@ -31,6 +36,8 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -38,10 +45,14 @@
import android.view.InputDevice;
import android.view.KeyEvent;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayDeque;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
import java.util.TreeMap;
/**
@@ -56,12 +67,36 @@
// 'adb shell setprop log.tag.KeyGestureController DEBUG' (requires restart)
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ // Maximum key gesture events that are tracked and will be available in input dump.
+ private static final int MAX_TRACKED_EVENTS = 10;
+
private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1;
+ // must match: config_settingsKeyBehavior in config.xml
+ private static final int SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0;
+ private static final int SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL = 1;
+ private static final int SETTINGS_KEY_BEHAVIOR_NOTHING = 2;
+ private static final int LAST_SETTINGS_KEY_BEHAVIOR = SETTINGS_KEY_BEHAVIOR_NOTHING;
+
+ // Must match: config_searchKeyBehavior in config.xml
+ private static final int SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH = 0;
+ private static final int SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY = 1;
+ private static final int LAST_SEARCH_KEY_BEHAVIOR = SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY;
+
private final Context mContext;
private final Handler mHandler;
private final int mSystemPid;
+ // Pending actions
+ private boolean mPendingMetaAction;
+ private boolean mPendingCapsLockToggle;
+ private boolean mPendingHideRecentSwitcher;
+
+ // Key behaviors
+ private boolean mEnableBugReportKeyboardShortcut;
+ private int mSearchKeyBehavior;
+ private int mSettingsKeyBehavior;
+
// List of currently registered key gesture event listeners keyed by process pid
@GuardedBy("mKeyGestureEventListenerRecords")
private final SparseArray<KeyGestureEventListenerRecord>
@@ -73,6 +108,11 @@
@GuardedBy("mKeyGestureHandlerRecords")
private final TreeMap<Integer, KeyGestureHandlerRecord> mKeyGestureHandlerRecords;
+ private final ArrayDeque<KeyGestureEvent> mLastHandledEvents = new ArrayDeque<>();
+
+ /** Currently fully consumed key codes per device */
+ private final SparseArray<Set<Integer>> mConsumedKeysForDevice = new SparseArray<>();
+
KeyGestureController(Context context, Looper looper) {
mContext = context;
mHandler = new Handler(looper, this::handleMessage);
@@ -89,12 +129,453 @@
return Integer.compare(p1, p2);
}
});
+ initBehaviors();
}
- public int interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
+ private void initBehaviors() {
+ mEnableBugReportKeyboardShortcut = "1".equals(SystemProperties.get("ro.debuggable"));
+
+ Resources res = mContext.getResources();
+ mSearchKeyBehavior = res.getInteger(R.integer.config_searchKeyBehavior);
+ if (mSearchKeyBehavior < SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH
+ || mSearchKeyBehavior > LAST_SEARCH_KEY_BEHAVIOR) {
+ mSearchKeyBehavior = SEARCH_KEY_BEHAVIOR_DEFAULT_SEARCH;
+ }
+ mSettingsKeyBehavior = res.getInteger(R.integer.config_settingsKeyBehavior);
+ if (mSettingsKeyBehavior < SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY
+ || mSettingsKeyBehavior > LAST_SETTINGS_KEY_BEHAVIOR) {
+ mSettingsKeyBehavior = SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY;
+ }
+ }
+
+ public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
+ int policyFlags) {
// TODO(b/358569822): Handle shortcuts trigger logic here and pass it to appropriate
// KeyGestureHandler (PWM is one of the handlers)
- return 0;
+ final int keyCode = event.getKeyCode();
+ final int deviceId = event.getDeviceId();
+ final long keyConsumed = -1;
+ final long keyNotConsumed = 0;
+
+ Set<Integer> consumedKeys = mConsumedKeysForDevice.get(deviceId);
+ if (consumedKeys == null) {
+ consumedKeys = new HashSet<>();
+ mConsumedKeysForDevice.put(deviceId, consumedKeys);
+ }
+
+ if (interceptSystemKeysAndShortcuts(focusedToken, event)
+ && event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+ consumedKeys.add(keyCode);
+ return keyConsumed;
+ }
+
+ boolean needToConsumeKey = consumedKeys.contains(keyCode);
+ if (event.getAction() == KeyEvent.ACTION_UP || event.isCanceled()) {
+ consumedKeys.remove(keyCode);
+ if (consumedKeys.isEmpty()) {
+ mConsumedKeysForDevice.remove(deviceId);
+ }
+ }
+
+ return needToConsumeKey ? keyConsumed : keyNotConsumed;
+ }
+
+ @SuppressLint("MissingPermission")
+ private boolean interceptSystemKeysAndShortcuts(IBinder focusedToken, KeyEvent event) {
+ final int keyCode = event.getKeyCode();
+ final int repeatCount = event.getRepeatCount();
+ final int metaState = event.getMetaState();
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ final boolean canceled = event.isCanceled();
+ final int displayId = event.getDisplayId();
+ final int deviceId = event.getDeviceId();
+ final boolean firstDown = down && repeatCount == 0;
+
+ // Cancel any pending meta actions if we see any other keys being pressed between the
+ // down of the meta key and its corresponding up.
+ if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
+ mPendingMetaAction = false;
+ }
+ // Any key that is not Alt or Meta cancels Caps Lock combo tracking.
+ if (mPendingCapsLockToggle && !KeyEvent.isMetaKey(keyCode) && !KeyEvent.isAltKey(keyCode)) {
+ mPendingCapsLockToggle = false;
+ }
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_A:
+ if (firstDown && event.isMetaPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_RECENT_APPS:
+ if (firstDown) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_APP_SWITCH:
+ if (firstDown) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
+ KeyGestureEvent.ACTION_GESTURE_START, displayId,
+ focusedToken, /* flags = */0);
+ } else if (!down) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, canceled ? KeyGestureEvent.FLAG_CANCELLED : 0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_H:
+ case KeyEvent.KEYCODE_ENTER:
+ if (firstDown && event.isMetaPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_I:
+ if (firstDown && event.isMetaPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_L:
+ if (firstDown && event.isMetaPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_N:
+ if (firstDown && event.isMetaPressed()) {
+ if (event.isCtrlPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ } else {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_S:
+ if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_DEL:
+ if (newBugreportKeyboardShortcut()) {
+ if (firstDown && mEnableBugReportKeyboardShortcut && event.isMetaPressed()
+ && event.isCtrlPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ // fall through
+ case KeyEvent.KEYCODE_ESCAPE:
+ if (firstDown && event.isMetaPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (firstDown && event.isMetaPressed()) {
+ if (event.isCtrlPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ } else if (event.isAltPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ } else {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (firstDown && event.isMetaPressed()) {
+ if (event.isCtrlPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ } else if (event.isAltPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_SLASH:
+ if (firstDown && event.isMetaPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ break;
+ case KeyEvent.KEYCODE_BRIGHTNESS_UP:
+ case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
+ if (down) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP
+ ? KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP
+ : KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN:
+ if (down) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP:
+ if (down) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE:
+ // TODO: Add logic
+ if (!down) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_ALL_APPS:
+ if (firstDown) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_NOTIFICATION:
+ if (!down) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_SEARCH:
+ if (firstDown && mSearchKeyBehavior == SEARCH_KEY_BEHAVIOR_TARGET_ACTIVITY) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+
+ }
+ break;
+ case KeyEvent.KEYCODE_SETTINGS:
+ if (firstDown) {
+ if (mSettingsKeyBehavior == SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY) {
+ handleKeyGesture(deviceId,
+ new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ } else if (mSettingsKeyBehavior == SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL) {
+ handleKeyGesture(deviceId,
+ new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ return true;
+ case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
+ if (firstDown) {
+ handleKeyGesture(deviceId, new int[]{keyCode},
+ event.isShiftPressed() ? KeyEvent.META_SHIFT_ON : 0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_CAPS_LOCK:
+ // Just logging/notifying purposes
+ // Caps lock is already handled in inputflinger native
+ if (!down) {
+ AidlKeyGestureEvent eventToNotify = createKeyGestureEvent(deviceId,
+ new int[]{keyCode}, metaState,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId, /* flags = */0);
+ Message msg = Message.obtain(mHandler, MSG_NOTIFY_KEY_GESTURE_EVENT,
+ eventToNotify);
+ mHandler.sendMessage(msg);
+ }
+ break;
+ case KeyEvent.KEYCODE_SCREENSHOT:
+ if (firstDown) {
+ handleKeyGesture(deviceId, new int[]{keyCode}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ return true;
+ case KeyEvent.KEYCODE_META_LEFT:
+ case KeyEvent.KEYCODE_META_RIGHT:
+ if (down) {
+ if (event.isAltPressed()) {
+ mPendingCapsLockToggle = true;
+ mPendingMetaAction = false;
+ } else {
+ mPendingCapsLockToggle = false;
+ mPendingMetaAction = true;
+ }
+ } else {
+ // Toggle Caps Lock on META-ALT.
+ if (mPendingCapsLockToggle) {
+ mPendingCapsLockToggle = false;
+ handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+
+ } else if (mPendingMetaAction) {
+ mPendingMetaAction = false;
+ if (!canceled) {
+ handleKeyGesture(deviceId, new int[]{keyCode},
+ /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ }
+ return true;
+ case KeyEvent.KEYCODE_TAB:
+ if (firstDown) {
+ if (event.isMetaPressed()) {
+ return handleKeyGesture(deviceId, new int[]{keyCode}, KeyEvent.META_META_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ } else if (!mPendingHideRecentSwitcher) {
+ final int shiftlessModifiers =
+ event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
+ if (KeyEvent.metaStateHasModifiers(
+ shiftlessModifiers, KeyEvent.META_ALT_ON)) {
+ mPendingHideRecentSwitcher = true;
+ return handleKeyGesture(deviceId, new int[]{keyCode},
+ KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER,
+ KeyGestureEvent.ACTION_GESTURE_START, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_ALT_LEFT:
+ case KeyEvent.KEYCODE_ALT_RIGHT:
+ if (down) {
+ if (event.isMetaPressed()) {
+ mPendingCapsLockToggle = true;
+ mPendingMetaAction = false;
+ } else {
+ mPendingCapsLockToggle = false;
+ }
+ } else {
+ if (mPendingHideRecentSwitcher) {
+ mPendingHideRecentSwitcher = false;
+ return handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_TAB},
+ KeyEvent.META_ALT_ON,
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+
+ // Toggle Caps Lock on META-ALT.
+ if (mPendingCapsLockToggle) {
+ mPendingCapsLockToggle = false;
+ return handleKeyGesture(deviceId, new int[]{KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT}, /* modifierState = */0,
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
+ focusedToken, /* flags = */0);
+ }
+ }
+ break;
+ case KeyEvent.KEYCODE_ASSIST:
+ Slog.wtf(TAG, "KEYCODE_ASSIST should be handled in interceptKeyBeforeQueueing");
+ return true;
+ case KeyEvent.KEYCODE_VOICE_ASSIST:
+ Slog.wtf(TAG, "KEYCODE_VOICE_ASSIST should be handled in"
+ + " interceptKeyBeforeQueueing");
+ return true;
+ case KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY:
+ case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY:
+ case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY:
+ case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL:
+ Slog.wtf(TAG, "KEYCODE_STYLUS_BUTTON_* should be handled in"
+ + " interceptKeyBeforeQueueing");
+ return true;
+ }
+ return false;
}
@VisibleForTesting
@@ -147,6 +628,10 @@
KeyGestureEvent.keyGestureTypeToLogEvent(event.gestureType));
}
notifyAllListeners(event);
+ while (mLastHandledEvents.size() >= MAX_TRACKED_EVENTS) {
+ mLastHandledEvents.removeFirst();
+ }
+ mLastHandledEvents.addLast(new KeyGestureEvent(event));
}
@MainThread
@@ -347,4 +832,45 @@
event.flags = flags;
return event;
}
+
+ public void dump(IndentingPrintWriter ipw) {
+ ipw.println("KeyGestureController:");
+ ipw.increaseIndent();
+ ipw.println("mSystemPid = " + mSystemPid);
+ ipw.println("mPendingMetaAction = " + mPendingMetaAction);
+ ipw.println("mPendingCapsLockToggle = " + mPendingCapsLockToggle);
+ ipw.println("mPendingHideRecentSwitcher = " + mPendingHideRecentSwitcher);
+ ipw.println("mSearchKeyBehavior = " + mSearchKeyBehavior);
+ ipw.println("mSettingsKeyBehavior = " + mSettingsKeyBehavior);
+ ipw.print("mKeyGestureEventListenerRecords = {");
+ synchronized (mKeyGestureEventListenerRecords) {
+ int size = mKeyGestureEventListenerRecords.size();
+ for (int i = 0; i < size; i++) {
+ ipw.print(mKeyGestureEventListenerRecords.keyAt(i));
+ if (i < size - 1) {
+ ipw.print(", ");
+ }
+ }
+ }
+ ipw.println("}");
+ ipw.print("mKeyGestureHandlerRecords = {");
+ synchronized (mKeyGestureHandlerRecords) {
+ int i = mKeyGestureHandlerRecords.size() - 1;
+ for (int processId : mKeyGestureHandlerRecords.keySet()) {
+ ipw.print(processId);
+ if (i > 0) {
+ ipw.print(", ");
+ }
+ i--;
+ }
+ }
+ ipw.println("}");
+ ipw.decreaseIndent();
+ ipw.println("Last handled KeyGestureEvents: ");
+ ipw.increaseIndent();
+ for (KeyGestureEvent ev : mLastHandledEvents) {
+ ipw.println(ev);
+ }
+ ipw.decreaseIndent();
+ }
}
diff --git a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
index cc13e8e..5ff8568 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadDebugView.java
@@ -29,11 +29,14 @@
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.ViewConfiguration;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.input.TouchpadFingerState;
import com.android.server.input.TouchpadHardwareProperties;
import com.android.server.input.TouchpadHardwareState;
@@ -47,11 +50,14 @@
private static final float TEXT_SIZE_SP = 16.0f;
private static final float DEFAULT_RES_X = 47f;
private static final float DEFAULT_RES_Y = 45f;
+ private static final int TEXT_PADDING_DP = 12;
+ private static final int ROUNDED_CORNER_RADIUS_DP = 24;
/**
* Input device ID for the touchpad that this debug view is displaying.
*/
private final int mTouchpadId;
+ private static final String TAG = "TouchpadDebugView";
@NonNull
private final WindowManager mWindowManager;
@@ -67,6 +73,8 @@
private int mScreenHeight;
private int mWindowLocationBeforeDragX;
private int mWindowLocationBeforeDragY;
+ private int mLatestGestureType = 0;
+ private TextView mGestureInfoView;
@NonNull
private TouchpadHardwareState mLastTouchpadState =
new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
@@ -75,7 +83,7 @@
private final TouchpadHardwareProperties mTouchpadHardwareProperties;
public TouchpadDebugView(Context context, int touchpadId,
- TouchpadHardwareProperties touchpadHardwareProperties) {
+ TouchpadHardwareProperties touchpadHardwareProperties) {
super(context);
mTouchpadId = touchpadId;
mWindowManager =
@@ -119,6 +127,9 @@
.getInputDevice(touchpadId)).getName());
nameView.setGravity(Gravity.CENTER);
nameView.setTextColor(Color.WHITE);
+ int paddingInDP = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, TEXT_PADDING_DP,
+ getResources().getDisplayMetrics());
+ nameView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP);
nameView.setLayoutParams(
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
@@ -126,24 +137,48 @@
mTouchpadHardwareProperties);
mTouchpadVisualizationView.setBackgroundColor(Color.WHITE);
- //TODO(b/365562952): Add a display for recognized gesture info here
- TextView gestureInfoView = new TextView(context);
- gestureInfoView.setBackgroundColor(Color.GRAY);
- gestureInfoView.setTextSize(TEXT_SIZE_SP);
- gestureInfoView.setText("Touchpad Debug View 3");
- gestureInfoView.setGravity(Gravity.CENTER);
- gestureInfoView.setTextColor(Color.BLACK);
- gestureInfoView.setLayoutParams(
+ mGestureInfoView = new TextView(context);
+ mGestureInfoView.setBackgroundColor(Color.BLACK);
+ mGestureInfoView.setTextSize(TEXT_SIZE_SP);
+ mGestureInfoView.setText("Latest Gesture: ");
+ mGestureInfoView.setGravity(Gravity.CENTER);
+ mGestureInfoView.setTextColor(Color.WHITE);
+ mGestureInfoView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP);
+ mGestureInfoView.setLayoutParams(
new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
addView(nameView);
addView(mTouchpadVisualizationView);
- addView(gestureInfoView);
+ addView(mGestureInfoView);
updateViewsDimensions();
}
@Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ postDelayed(() -> {
+ final ViewRootImpl viewRootImpl = getRootView().getViewRootImpl();
+ if (viewRootImpl == null) {
+ Slog.d("TouchpadDebugView", "ViewRootImpl is null.");
+ return;
+ }
+
+ SurfaceControl surfaceControl = viewRootImpl.getSurfaceControl();
+ if (surfaceControl != null && surfaceControl.isValid()) {
+ try (SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
+ transaction.setCornerRadius(surfaceControl,
+ TypedValue.applyDimension(COMPLEX_UNIT_DIP,
+ ROUNDED_CORNER_RADIUS_DP,
+ getResources().getDisplayMetrics())).apply();
+ }
+ } else {
+ Slog.d("TouchpadDebugView", "SurfaceControl is invalid or has been released.");
+ }
+ }, 100);
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent event) {
float deltaX;
float deltaY;
@@ -193,7 +228,7 @@
@Override
public boolean performClick() {
super.performClick();
- Slog.d("TouchpadDebugView", "You tapped the window!");
+ Slog.d(TAG, "You tapped the window!");
return true;
}
@@ -265,12 +300,14 @@
return mWindowLayoutParams;
}
+ @VisibleForTesting
+ TextView getGestureInfoView() {
+ return mGestureInfoView;
+ }
+
/**
- * Notify the view of a change in the hardware state of a touchpad. The view should
- * update its content to reflect the new state.
- *
- * @param touchpadHardwareState the hardware state of a touchpad
- * @param deviceId the deviceId of the touchpad that is sending the hardware state
+ * Notify the view of a change in TouchpadHardwareState and changing the
+ * color of the view based on the status of the button click.
*/
public void updateHardwareState(TouchpadHardwareState touchpadHardwareState, int deviceId) {
if (deviceId != mTouchpadId) {
@@ -291,12 +328,43 @@
}
private void onTouchpadButtonPress() {
- Slog.d("TouchpadDebugView", "You clicked me!");
+ Slog.d(TAG, "You clicked me!");
getChildAt(0).setBackgroundColor(Color.BLUE);
}
private void onTouchpadButtonRelease() {
- Slog.d("TouchpadDebugView", "You released the click");
+ Slog.d(TAG, "You released the click");
getChildAt(0).setBackgroundColor(Color.RED);
}
+
+ /**
+ * Notify the view of any new gesture on the touchpad and displaying its name
+ */
+ public void updateGestureInfo(int newGestureType, int deviceId) {
+ if (deviceId == mTouchpadId && mLatestGestureType != newGestureType) {
+ mGestureInfoView.setText(getGestureText(newGestureType));
+ mLatestGestureType = newGestureType;
+ }
+ }
+
+ @NonNull
+ static String getGestureText(int gestureType) {
+ // These values are a representation of the GestureType enum in the
+ // external/libchrome-gestures/include/gestures.h library in the C++ code
+ String mGestureName = switch (gestureType) {
+ case 1 -> "Move, 1 Finger";
+ case 2 -> "Scroll, 2 Fingers";
+ case 3 -> "Buttons Change, 1 Fingers";
+ case 4 -> "Fling";
+ case 5 -> "Swipe, 3 Fingers";
+ case 6 -> "Pinch, 2 Fingers";
+ case 7 -> "Swipe Lift, 3 Fingers";
+ case 8 -> "Metrics";
+ case 9 -> "Four Finger Swipe, 4 Fingers";
+ case 10 -> "Four Finger Swipe Lift, 4 Fingers";
+ case 11 -> "Mouse Wheel";
+ default -> "Unknown Gesture";
+ };
+ return "Latest Gesture: " + mGestureName;
+ }
}
diff --git a/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java b/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java
index b4b357a..cb43977 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadDebugViewController.java
@@ -155,4 +155,13 @@
mTouchpadDebugView.updateHardwareState(touchpadHardwareState, deviceId);
}
}
+
+ /**
+ * Notify the TouchpadDebugView of a new touchpad gesture.
+ */
+ public void updateTouchpadGestureInfo(int gestureType, int deviceId) {
+ if (mTouchpadDebugView != null) {
+ mTouchpadDebugView.updateGestureInfo(gestureType, deviceId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
index 2ed6f44..2eed9ba 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
@@ -27,55 +27,97 @@
import com.android.server.input.TouchpadHardwareProperties;
import com.android.server.input.TouchpadHardwareState;
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.Map;
+
public class TouchpadVisualizationView extends View {
private static final String TAG = "TouchpadVizMain";
private static final boolean DEBUG = true;
private static final float DEFAULT_RES_X = 47f;
private static final float DEFAULT_RES_Y = 45f;
+ private static final float MAX_TRACE_HISTORY_DURATION_SECONDS = 1f;
private final TouchpadHardwareProperties mTouchpadHardwareProperties;
private float mScaleFactor;
- TouchpadHardwareState mLatestHardwareState = new TouchpadHardwareState(0, 0, 0, 0,
- new TouchpadFingerState[]{});
+ private final ArrayDeque<TouchpadHardwareState> mHardwareStateHistory =
+ new ArrayDeque<TouchpadHardwareState>();
+ private final Map<Integer, TouchpadFingerState> mTempFingerStatesByTrackingId = new HashMap<>();
- private final Paint mOvalPaint;
+ private final Paint mOvalStrokePaint;
+ private final Paint mOvalFillPaint;
+ private final Paint mTracePaint;
+ private final Paint mCenterPointPaint;
+ private final RectF mTempOvalRect = new RectF();
public TouchpadVisualizationView(Context context,
TouchpadHardwareProperties touchpadHardwareProperties) {
super(context);
mTouchpadHardwareProperties = touchpadHardwareProperties;
mScaleFactor = 1;
- mOvalPaint = new Paint();
- mOvalPaint.setAntiAlias(true);
- mOvalPaint.setARGB(255, 0, 0, 0);
- mOvalPaint.setStyle(Paint.Style.STROKE);
+ mOvalStrokePaint = new Paint();
+ mOvalStrokePaint.setAntiAlias(true);
+ mOvalStrokePaint.setARGB(255, 0, 0, 0);
+ mOvalStrokePaint.setStyle(Paint.Style.STROKE);
+ mOvalFillPaint = new Paint();
+ mOvalFillPaint.setAntiAlias(true);
+ mOvalFillPaint.setARGB(255, 0, 0, 0);
+ mTracePaint = new Paint();
+ mTracePaint.setAntiAlias(false);
+ mTracePaint.setARGB(255, 0, 0, 255);
+ mTracePaint.setStyle(Paint.Style.STROKE);
+ mTracePaint.setStrokeWidth(2);
+ mCenterPointPaint = new Paint();
+ mCenterPointPaint.setAntiAlias(true);
+ mCenterPointPaint.setARGB(255, 255, 0, 0);
+ mCenterPointPaint.setStrokeWidth(2);
}
- private final RectF mOvalRect = new RectF();
+ private void removeOldPoints() {
+ float latestTimestamp = mHardwareStateHistory.getLast().getTimestamp();
- private void drawOval(Canvas canvas, float x, float y, float major, float minor, float angle,
- Paint paint) {
+ while (!mHardwareStateHistory.isEmpty()) {
+ TouchpadHardwareState oldestPoint = mHardwareStateHistory.getFirst();
+ float onScreenTime = latestTimestamp - oldestPoint.getTimestamp();
+ if (onScreenTime >= MAX_TRACE_HISTORY_DURATION_SECONDS) {
+ mHardwareStateHistory.removeFirst();
+ } else {
+ break;
+ }
+ }
+ }
+
+ private void drawOval(Canvas canvas, float x, float y, float major, float minor, float angle) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(angle, x, y);
- mOvalRect.left = x - minor / 2;
- mOvalRect.right = x + minor / 2;
- mOvalRect.top = y - major / 2;
- mOvalRect.bottom = y + major / 2;
- canvas.drawOval(mOvalRect, paint);
+ mTempOvalRect.left = x - minor / 2;
+ mTempOvalRect.right = x + minor / 2;
+ mTempOvalRect.top = y - major / 2;
+ mTempOvalRect.bottom = y + major / 2;
+ canvas.drawOval(mTempOvalRect, mOvalStrokePaint);
+ canvas.drawOval(mTempOvalRect, mOvalFillPaint);
canvas.restore();
}
@Override
protected void onDraw(Canvas canvas) {
- for (TouchpadFingerState touchpadFingerState : mLatestHardwareState.getFingerStates()) {
- float newX = translateRange(mTouchpadHardwareProperties.getLeft(),
- mTouchpadHardwareProperties.getRight(), 0, getWidth(),
- touchpadFingerState.getPositionX());
+ if (mHardwareStateHistory.isEmpty()) {
+ return;
+ }
- float newY = translateRange(mTouchpadHardwareProperties.getTop(),
- mTouchpadHardwareProperties.getBottom(), 0, getHeight(),
- touchpadFingerState.getPositionY());
+ TouchpadHardwareState latestHardwareState = mHardwareStateHistory.getLast();
+
+ float maximumPressure = 0;
+ for (TouchpadFingerState touchpadFingerState : latestHardwareState.getFingerStates()) {
+ maximumPressure = Math.max(maximumPressure, touchpadFingerState.getPressure());
+ }
+
+ // Visualizing fingers as ovals
+ for (TouchpadFingerState touchpadFingerState : latestHardwareState.getFingerStates()) {
+ float newX = translateX(touchpadFingerState.getPositionX());
+
+ float newY = translateY(touchpadFingerState.getPositionY());
float newAngle = translateRange(0, mTouchpadHardwareProperties.getOrientationMaximum(),
0, 90, touchpadFingerState.getOrientation());
@@ -88,7 +130,33 @@
float newTouchMajor = touchpadFingerState.getTouchMajor() * mScaleFactor / resY;
float newTouchMinor = touchpadFingerState.getTouchMinor() * mScaleFactor / resX;
- drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle, mOvalPaint);
+ float pressureToOpacity = translateRange(0, maximumPressure, 0, 255,
+ touchpadFingerState.getPressure());
+ mOvalFillPaint.setAlpha((int) pressureToOpacity);
+
+ drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle);
+ }
+
+ mTempFingerStatesByTrackingId.clear();
+
+ // Drawing the trace
+ for (TouchpadHardwareState currentHardwareState : mHardwareStateHistory) {
+ for (TouchpadFingerState currentFingerState : currentHardwareState.getFingerStates()) {
+ TouchpadFingerState prevFingerState = mTempFingerStatesByTrackingId.put(
+ currentFingerState.getTrackingId(), currentFingerState);
+
+ if (prevFingerState == null) {
+ continue;
+ }
+
+ float currentX = translateX(currentFingerState.getPositionX());
+ float currentY = translateY(currentFingerState.getPositionY());
+ float prevX = translateX(prevFingerState.getPositionX());
+ float prevY = translateY(prevFingerState.getPositionY());
+
+ canvas.drawLine(prevX, prevY, currentX, currentY, mTracePaint);
+ canvas.drawPoint(currentX, currentY, mCenterPointPaint);
+ }
}
}
@@ -102,7 +170,18 @@
logHardwareState(schs);
}
- mLatestHardwareState = schs;
+ if (!mHardwareStateHistory.isEmpty()
+ && mHardwareStateHistory.getLast().getFingerCount() == 0
+ && schs.getFingerCount() > 0) {
+ mHardwareStateHistory.clear();
+ }
+
+ mHardwareStateHistory.addLast(schs);
+ removeOldPoints();
+
+ if (DEBUG) {
+ logFingerTrace();
+ }
invalidate();
}
@@ -116,6 +195,16 @@
mScaleFactor = scaleFactor;
}
+ private float translateX(float x) {
+ return translateRange(mTouchpadHardwareProperties.getLeft(),
+ mTouchpadHardwareProperties.getRight(), 0, getWidth(), x);
+ }
+
+ private float translateY(float y) {
+ return translateRange(mTouchpadHardwareProperties.getTop(),
+ mTouchpadHardwareProperties.getBottom(), 0, getHeight(), y);
+ }
+
private float translateRange(float rangeBeforeMin, float rangeBeforeMax,
float rangeAfterMin, float rangeAfterMax, float value) {
return rangeAfterMin + (value - rangeBeforeMin) / (rangeBeforeMax - rangeBeforeMin) * (
@@ -142,4 +231,10 @@
}
}
-}
+ private void logFingerTrace() {
+ Slog.d(TAG, "Trace size= " + mHardwareStateHistory.size());
+ for (TouchpadFingerState tfs : mHardwareStateHistory.getLast().getFingerStates()) {
+ Slog.d(TAG, "ID= " + tfs.getTrackingId());
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index f747879..2bb2b7b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -6107,7 +6107,22 @@
final int argUserId = parseUserIdFromDumpArgs(args);
final Printer p = new PrintWriterPrinter(pw);
p.println("Current Input Method Manager state:");
- p.println(" concurrentMultiUserModeEnabled=" + mConcurrentMultiUserModeEnabled);
+ p.println(" mSystemReady=" + mSystemReady);
+ p.println(" mInteractive=" + mIsInteractive);
+ p.println(" mConcurrentMultiUserModeEnabled=" + mConcurrentMultiUserModeEnabled);
+ p.println(" ENABLE_HIDE_IME_CAPTION_BAR="
+ + InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR);
+ synchronized (ImfLock.class) {
+ p.println(" mStylusIds=" + (mStylusIds != null
+ ? Arrays.toString(mStylusIds.toArray()) : ""));
+ }
+ if (Flags.imeSwitcherRevamp()) {
+ p.println(" mMenuControllerNew:");
+ mMenuControllerNew.dump(p, " ");
+ } else {
+ p.println(" mMenuController:");
+ mMenuController.dump(p, " ");
+ }
if (mConcurrentMultiUserModeEnabled && argUserId == UserHandle.USER_NULL) {
mUserDataRepository.forAllUserData(
u -> dumpAsStringNoCheckForUser(u, fd, pw, args, isCritical));
@@ -6116,6 +6131,22 @@
final var userData = getUserData(userId);
dumpAsStringNoCheckForUser(userData, fd, pw, args, isCritical);
}
+
+ // TODO(b/365868861): Make StartInputHistory, SoftInputShowHideHistory and ImeTracker per
+ // user.
+ synchronized (ImfLock.class) {
+ p.println(" mStartInputHistory:");
+ mStartInputHistory.dump(pw, " ");
+
+ p.println(" mSoftInputShowHideHistory:");
+ mSoftInputShowHideHistory.dump(pw, " ");
+ }
+
+ p.println(" mImeTrackerService#History:");
+ mImeTrackerService.dump(pw, " ");
+
+ dumpUserRepository(p);
+ dumpClientStates(p);
}
@UserIdInt
@@ -6140,104 +6171,33 @@
userData.mUserId);
final List<InputMethodInfo> methodList = settings.getMethodList();
int numImes = methodList.size();
- p.println(" Input Methods:");
+ p.println(" Input Methods:");
for (int i = 0; i < numImes; i++) {
InputMethodInfo info = methodList.get(i);
- p.println(" InputMethod #" + i + ":");
- info.dump(p, " ");
+ p.println(" InputMethod #" + i + ":");
+ info.dump(p, " ");
}
- // Dump ClientController#mClients
- p.println(" ClientStates:");
- // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
- @SuppressWarnings("GuardedBy") Consumer<ClientState> clientControllerDump = c -> {
- p.println(" " + c + ":");
- p.println(" client=" + c.mClient);
- p.println(" fallbackInputConnection="
- + c.mFallbackInputConnection);
- p.println(" sessionRequested="
- + c.mSessionRequested);
- p.println(" sessionRequestedForAccessibility="
- + c.mSessionRequestedForAccessibility);
- p.println(" curSession=" + c.mCurSession);
- p.println(" selfReportedDisplayId=" + c.mSelfReportedDisplayId);
- p.println(" uid=" + c.mUid);
- p.println(" pid=" + c.mPid);
- };
- mClientController.forAllClients(clientControllerDump);
final var bindingController = userData.mBindingController;
- p.println(" mCurMethodId=" + bindingController.getSelectedMethodId());
+ p.println(" mCurMethodId=" + bindingController.getSelectedMethodId());
client = userData.mCurClient;
- p.println(" mCurClient=" + client + " mCurSeq="
+ p.println(" mCurClient=" + client + " mCurSeq="
+ bindingController.getSequenceNumber());
- p.println(" mFocusedWindowPerceptible=" + mFocusedWindowPerceptible);
+ p.println(" mFocusedWindowPerceptible=" + mFocusedWindowPerceptible);
userData.mImeBindingState.dump(/* prefix= */ " ", p);
-
- p.println(" mCurId=" + bindingController.getCurId()
- + " mHaveConnection=" + bindingController.hasMainConnection()
- + " mBoundToMethod=" + userData.mBoundToMethod + " mVisibleBound="
- + bindingController.isVisibleBound());
-
- p.println(" mUserDataRepository=");
- // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
- @SuppressWarnings("GuardedBy") Consumer<UserData> userDataDump =
- u -> {
- p.println(" mUserId=" + u.mUserId);
- p.println(" unlocked=" + u.mIsUnlockingOrUnlocked.get());
- p.println(" hasMainConnection="
- + u.mBindingController.hasMainConnection());
- p.println(" isVisibleBound=" + u.mBindingController.isVisibleBound());
- p.println(" boundToMethod=" + u.mBoundToMethod);
- p.println(" curClient=" + u.mCurClient);
- if (u.mCurEditorInfo != null) {
- p.println(" curEditorInfo:");
- u.mCurEditorInfo.dump(p, " ", false /* dumpExtras */);
- } else {
- p.println(" curEditorInfo: null");
- }
- p.println(" imeBindingState:");
- u.mImeBindingState.dump(" ", p);
- p.println(" enabledSession=" + u.mEnabledSession);
- p.println(" inFullscreenMode=" + u.mInFullscreenMode);
- p.println(" imeDrawsNavBar=" + u.mImeDrawsNavBar.get());
- p.println(" switchingController:");
- u.mSwitchingController.dump(p, " ");
- p.println(" mLastEnabledInputMethodsStr="
- + u.mLastEnabledInputMethodsStr);
- };
- mUserDataRepository.forAllUserData(userDataDump);
-
- if (Flags.imeSwitcherRevamp()) {
- p.println(" menuControllerNew:");
- mMenuControllerNew.dump(p, " ");
- } else {
- p.println(" menuController:");
- mMenuController.dump(p, " ");
- }
- p.println(" mCurToken=" + bindingController.getCurToken());
- p.println(" mCurTokenDisplayId=" + bindingController.getCurTokenDisplayId());
- p.println(" mCurHostInputToken=" + bindingController.getCurHostInputToken());
- p.println(" mCurIntent=" + bindingController.getCurIntent());
+ p.println(" mCurId=" + bindingController.getCurId());
+ p.println(" mHaveConnection=" + bindingController.hasMainConnection());
+ p.println(" mBoundToMethod=" + userData.mBoundToMethod);
+ p.println(" mVisibleBound=" + bindingController.isVisibleBound());
+ p.println(" mCurToken=" + bindingController.getCurToken());
+ p.println(" mCurTokenDisplayId=" + bindingController.getCurTokenDisplayId());
+ p.println(" mCurHostInputToken=" + bindingController.getCurHostInputToken());
+ p.println(" mCurIntent=" + bindingController.getCurIntent());
method = bindingController.getCurMethod();
- p.println(" mCurMethod=" + method);
- p.println(" mEnabledSession=" + userData.mEnabledSession);
+ p.println(" mCurMethod=" + method);
+ p.println(" mEnabledSession=" + userData.mEnabledSession);
final var visibilityStateComputer = userData.mVisibilityStateComputer;
visibilityStateComputer.dump(pw, " ");
- p.println(" mInFullscreenMode=" + userData.mInFullscreenMode);
- p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
- p.println(" mConcurrentMultiUserModeEnabled=" + mConcurrentMultiUserModeEnabled);
- p.println(" ENABLE_HIDE_IME_CAPTION_BAR="
- + InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR);
- p.println(" mStylusIds=" + (mStylusIds != null
- ? Arrays.toString(mStylusIds.toArray()) : ""));
-
- p.println(" mStartInputHistory:");
- mStartInputHistory.dump(pw, " ");
-
- p.println(" mSoftInputShowHideHistory:");
- mSoftInputShowHideHistory.dump(pw, " ");
-
- p.println(" mImeTrackerService#History:");
- mImeTrackerService.dump(pw, " ");
+ p.println(" mInFullscreenMode=" + userData.mInFullscreenMode);
}
// Exit here for critical dump, as remaining sections require IPCs to other processes.
@@ -6288,6 +6248,61 @@
}
}
+ private void dumpClientStates(Printer p) {
+ p.println(" ClientStates:");
+ // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
+ @SuppressWarnings("GuardedBy") Consumer<ClientState> clientControllerDump = c -> {
+ p.println(" " + c + ":");
+ p.println(" client=" + c.mClient);
+ p.println(" fallbackInputConnection="
+ + c.mFallbackInputConnection);
+ p.println(" sessionRequested="
+ + c.mSessionRequested);
+ p.println(" sessionRequestedForAccessibility="
+ + c.mSessionRequestedForAccessibility);
+ p.println(" curSession=" + c.mCurSession);
+ p.println(" selfReportedDisplayId=" + c.mSelfReportedDisplayId);
+ p.println(" uid=" + c.mUid);
+ p.println(" pid=" + c.mPid);
+ };
+ synchronized (ImfLock.class) {
+ mClientController.forAllClients(clientControllerDump);
+ }
+ }
+
+ private void dumpUserRepository(Printer p) {
+ p.println(" mUserDataRepository=");
+ // TODO(b/324907325): Remove the suppress warnings once b/324907325 is fixed.
+ @SuppressWarnings("GuardedBy") Consumer<UserData> userDataDump =
+ u -> {
+ p.println(" mUserId=" + u.mUserId);
+ p.println(" unlocked=" + u.mIsUnlockingOrUnlocked.get());
+ p.println(" hasMainConnection="
+ + u.mBindingController.hasMainConnection());
+ p.println(" isVisibleBound=" + u.mBindingController.isVisibleBound());
+ p.println(" boundToMethod=" + u.mBoundToMethod);
+ p.println(" curClient=" + u.mCurClient);
+ if (u.mCurEditorInfo != null) {
+ p.println(" curEditorInfo:");
+ u.mCurEditorInfo.dump(p, " ", false /* dumpExtras */);
+ } else {
+ p.println(" curEditorInfo: null");
+ }
+ p.println(" imeBindingState:");
+ u.mImeBindingState.dump(" ", p);
+ p.println(" enabledSession=" + u.mEnabledSession);
+ p.println(" inFullscreenMode=" + u.mInFullscreenMode);
+ p.println(" imeDrawsNavBar=" + u.mImeDrawsNavBar.get());
+ p.println(" switchingController:");
+ u.mSwitchingController.dump(p, " ");
+ p.println(" mLastEnabledInputMethodsStr="
+ + u.mLastEnabledInputMethodsStr);
+ };
+ synchronized (ImfLock.class) {
+ mUserDataRepository.forAllUserData(userDataDump);
+ }
+ }
+
@BinderThread
@Override
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
diff --git a/services/core/java/com/android/server/lights/TEST_MAPPING b/services/core/java/com/android/server/lights/TEST_MAPPING
index 1d2cd3c..8abdf00 100644
--- a/services/core/java/com/android/server/lights/TEST_MAPPING
+++ b/services/core/java/com/android/server/lights/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsHardwareTestCases",
- "options": [
- {"include-filter": "com.android.hardware.lights"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"}
- ]
+ "name": "CtsHardwareTestCases_hardware_lights"
},
{
"name": "FrameworksServicesTests_android_server_lights"
diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING
index 64b1ed2..b2ac7d1 100644
--- a/services/core/java/com/android/server/location/TEST_MAPPING
+++ b/services/core/java/com/android/server/location/TEST_MAPPING
@@ -1,13 +1,7 @@
{
"presubmit": [
{
- "name": "CtsLocationFineTestCases",
- "options": [
- {
- // TODO: Wait for test to deflake - b/293934372
- "exclude-filter":"android.location.cts.fine.ScanningSettingsTest"
- }
- ]
+ "name": "CtsLocationFineTestCases_android_server_location"
},
{
"name": "CtsLocationCoarseTestCases"
diff --git a/services/core/java/com/android/server/locksettings/Android.bp b/services/core/java/com/android/server/locksettings/Android.bp
new file mode 100644
index 0000000..53f1ac6
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/Android.bp
@@ -0,0 +1,11 @@
+aconfig_declarations {
+ name: "locksettings_flags",
+ package: "com.android.server.locksettings",
+ container: "system",
+ srcs: ["*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "locksettings_flags_lib",
+ aconfig_declarations: "locksettings_flags",
+}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index f44b852..820c0ef 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -273,11 +273,6 @@
"server_based_ror_enabled", false);
}
- public boolean waitForInternet() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_OTA, "wait_for_internet_ror", false);
- }
-
public boolean isNetworkConnected() {
final ConnectivityManager connectivityManager =
mContext.getSystemService(ConnectivityManager.class);
@@ -433,7 +428,7 @@
/** Wrapper function to set error code serialized through handler, */
private void setLoadEscrowDataErrorCode(@RebootEscrowErrorCode int value, Handler handler) {
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
mInjector.post(
handler,
() -> {
@@ -516,7 +511,7 @@
mWakeLock.acquire(mInjector.getWakeLockTimeoutMillis());
}
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
// Timeout to stop retrying same as the wake lock timeout.
mInjector.postDelayed(
retryHandler,
@@ -553,7 +548,7 @@
return;
}
- if (mInjector.waitForInternet()) {
+ if (Flags.waitForInternetRor()) {
if (mRebootEscrowTimedOut) {
Slog.w(TAG, "Failed to load reboot escrow data within timeout");
compareAndSetLoadEscrowDataErrorCode(
diff --git a/services/core/java/com/android/server/locksettings/TEST_MAPPING b/services/core/java/com/android/server/locksettings/TEST_MAPPING
index ffbdf7f..d338c50 100644
--- a/services/core/java/com/android/server/locksettings/TEST_MAPPING
+++ b/services/core/java/com/android/server/locksettings/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit-large": [
{
- "name": "CtsDevicePolicyManagerTestCases",
- "options": [
- {
- "include-annotation": "com.android.cts.devicepolicy.annotations.LockSettingsTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsDevicePolicyManagerTestCases_LockSettingsTest"
}
],
"presubmit": [
diff --git a/services/core/java/com/android/server/locksettings/flags.aconfig b/services/core/java/com/android/server/locksettings/flags.aconfig
new file mode 100644
index 0000000..6818de9
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.server.locksettings"
+container: "system"
+
+flag {
+ name: "wait_for_internet_ror"
+ namespace: "sudo"
+ description: "Feature flag to wait for internet connectivity before calling resume on reboot server."
+ bug: "231660348"
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/media/AudioManagerRouteController.java b/services/core/java/com/android/server/media/AudioManagerRouteController.java
index f27ade4..c79f41d 100644
--- a/services/core/java/com/android/server/media/AudioManagerRouteController.java
+++ b/services/core/java/com/android/server/media/AudioManagerRouteController.java
@@ -442,7 +442,7 @@
@Nullable
private MediaRoute2Info createMediaRoute2Info(
@Nullable String routeId,
- int audioDeviceInfoType,
+ @AudioDeviceInfo.AudioDeviceType int audioDeviceInfoType,
@Nullable CharSequence deviceName,
@Nullable String address) {
SystemRouteInfo systemRouteInfo =
@@ -490,7 +490,8 @@
public final boolean mCorrespondsToInactiveBluetoothRoute;
public static MediaRoute2InfoHolder createForAudioManagerRoute(
- MediaRoute2Info mediaRoute2Info, int audioDeviceInfoType) {
+ MediaRoute2Info mediaRoute2Info,
+ @AudioDeviceInfo.AudioDeviceType int audioDeviceInfoType) {
return new MediaRoute2InfoHolder(
mediaRoute2Info,
audioDeviceInfoType,
@@ -509,7 +510,7 @@
private MediaRoute2InfoHolder(
MediaRoute2Info mediaRoute2Info,
- int audioDeviceInfoType,
+ @AudioDeviceInfo.AudioDeviceType int audioDeviceInfoType,
boolean correspondsToInactiveBluetoothRoute) {
mMediaRoute2Info = mediaRoute2Info;
mAudioDeviceInfoType = audioDeviceInfoType;
diff --git a/services/core/java/com/android/server/media/projection/TEST_MAPPING b/services/core/java/com/android/server/media/projection/TEST_MAPPING
index 7aa9118..b33097c 100644
--- a/services/core/java/com/android/server/media/projection/TEST_MAPPING
+++ b/services/core/java/com/android/server/media/projection/TEST_MAPPING
@@ -1,15 +1,7 @@
{
"presubmit": [
{
- "name": "MediaProjectionTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "MediaProjectionTests"
}
]
}
diff --git a/services/core/java/com/android/server/net/TEST_MAPPING b/services/core/java/com/android/server/net/TEST_MAPPING
index ad6b0ca..d95849e 100644
--- a/services/core/java/com/android/server/net/TEST_MAPPING
+++ b/services/core/java/com/android/server/net/TEST_MAPPING
@@ -1,40 +1,16 @@
{
"presubmit-large": [
{
- "name": "CtsHostsideNetworkPolicyTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- }
- ]
+ "name": "CtsHostsideNetworkPolicyTests"
}
],
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "file_patterns": ["(/|^)Network(Policy|Management)[^/]*\\.java"],
- "options": [
- {
- "include-filter": "com.android.server.net."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksServicesTests_android_server_net_Presubmit",
+ "file_patterns": ["(/|^)Network(Policy|Management)[^/]*\\.java"]
},
{
- "name": "FrameworksVpnTests",
- "options": [
- {
- "exclude-annotation": "com.android.testutils.SkipPresubmit"
- }
- ],
+ "name": "FrameworksVpnTests_android_server_connectivity",
"file_patterns": ["VpnManagerService\\.java"]
}
]
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java
index 4fa7112..9d30c56 100644
--- a/services/core/java/com/android/server/notification/GroupHelper.java
+++ b/services/core/java/com/android/server/notification/GroupHelper.java
@@ -757,8 +757,12 @@
// scenario 3: sparse/singleton groups
if (Flags.notificationForceGroupSingletons()) {
- groupSparseGroups(record, notificationList, summaryByGroupKey, sectioner,
- fullAggregateGroupKey);
+ try {
+ groupSparseGroups(record, notificationList, summaryByGroupKey, sectioner,
+ fullAggregateGroupKey);
+ } catch (Throwable e) {
+ Slog.wtf(TAG, "Failed to group sparse groups", e);
+ }
}
}
}
@@ -1193,6 +1197,11 @@
final ArrayMap<String, NotificationAttributes> aggregatedNotificationsAttrs =
mAggregatedNotifications.getOrDefault(fullAggregateGroupKey, new ArrayMap<>());
final boolean hasSummary = !aggregatedNotificationsAttrs.isEmpty();
+ String triggeringKey = null;
+ if (!record.getNotification().isGroupSummary()) {
+ // Use this record as triggeringKey only if not a group summary (will be removed)
+ triggeringKey = record.getKey();
+ }
for (NotificationRecord r : notificationList) {
// Add notifications for detected sparse groups
if (sparseGroupSummaries.containsKey(r.getGroupKey())) {
@@ -1209,6 +1218,10 @@
r.getNotification().getGroupAlertBehavior(),
r.getChannel().getId()));
+ // Pick the first valid triggeringKey
+ if (triggeringKey == null) {
+ triggeringKey = r.getKey();
+ }
} else if (r.getNotification().isGroupSummary()) {
// Remove summary notifications
if (DEBUG) {
@@ -1231,7 +1244,7 @@
mAggregatedNotifications.put(fullAggregateGroupKey, aggregatedNotificationsAttrs);
// add/update aggregate summary
- updateAggregateAppGroup(fullAggregateGroupKey, record.getKey(), hasSummary,
+ updateAggregateAppGroup(fullAggregateGroupKey, triggeringKey, hasSummary,
sectioner.mSummaryId);
//cleanup mUngroupedAbuseNotifications
diff --git a/services/core/java/com/android/server/notification/TEST_MAPPING b/services/core/java/com/android/server/notification/TEST_MAPPING
index 468c451..dc7129cd 100644
--- a/services/core/java/com/android/server/notification/TEST_MAPPING
+++ b/services/core/java/com/android/server/notification/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "CtsNotificationTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsNotificationTestCases_notification"
},
{
- "name": "FrameworksUiServicesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "FrameworksUiServicesTests_notification"
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index d495ef5..50bfbc3 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -157,7 +157,7 @@
}
// empty rule? disable and bail early
if (rule.component == null && rule.enabler == null) {
- if (!android.app.Flags.modesUi() || (android.app.Flags.modesUi() && !isManual)) {
+ if (!isManual) {
Log.w(TAG, "No component found for automatic rule: " + rule.conditionId);
rule.enabled = false;
}
diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
index b03a54e..fcc5e97 100644
--- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java
+++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
@@ -419,7 +419,7 @@
if (config.automaticRules != null) {
for (ZenModeConfig.ZenRule rule : config.automaticRules.values()) {
- if (rule != null && rule.isAutomaticActive()) {
+ if (rule != null && rule.isActive()) {
rules.add(rule);
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 2ada9ae4..e9db1b5 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -887,7 +887,7 @@
return Condition.STATE_UNKNOWN;
}
if (Flags.modesApi() && Flags.modesUi()) {
- return rule.isAutomaticActive() ? STATE_TRUE : STATE_FALSE;
+ return rule.isActive() ? STATE_TRUE : STATE_FALSE;
} else {
// Buggy, does not consider snoozing!
return rule.condition != null ? rule.condition.state : STATE_FALSE;
@@ -967,12 +967,12 @@
// snoozing-unsnoozing or activating-stopping.
if (condition.state == STATE_TRUE) {
rule.resetConditionOverride();
- if (!rule.isAutomaticActive()) {
+ if (!rule.isActive()) {
rule.setConditionOverride(OVERRIDE_ACTIVATE);
}
} else if (condition.state == STATE_FALSE) {
rule.resetConditionOverride();
- if (rule.isAutomaticActive()) {
+ if (rule.isActive()) {
rule.setConditionOverride(OVERRIDE_DEACTIVATE);
}
}
@@ -1609,7 +1609,7 @@
// User deactivation of DND means just turning off the manual DND rule.
// For API calls (different origin) keep old behavior of snoozing all rules.
for (ZenRule automaticRule : newConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
automaticRule.setConditionOverride(OVERRIDE_DEACTIVATE);
}
}
@@ -1618,7 +1618,7 @@
if (zenMode == Global.ZEN_MODE_OFF) {
newConfig.manualRule = null;
for (ZenRule automaticRule : newConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
automaticRule.setConditionOverride(OVERRIDE_DEACTIVATE);
}
}
@@ -1665,7 +1665,7 @@
mConfig.manualRule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
}
for (ZenRule rule : mConfig.automaticRules.values()) {
- if (rule.isAutomaticActive()) {
+ if (rule.isActive()) {
rule.dumpDebug(proto, ZenModeProto.ENABLED_ACTIVE_CONDITIONS);
}
}
@@ -2020,9 +2020,9 @@
scheduleEnabledBroadcast(
rule.getPkg(), config.user, rule.id, rule.enabled);
}
- if (original.isAutomaticActive() != rule.isAutomaticActive()) {
+ if (original.isActive() != rule.isActive()) {
scheduleActivationBroadcast(
- rule.getPkg(), config.user, rule.id, rule.isAutomaticActive());
+ rule.getPkg(), config.user, rule.id, rule.isActive());
}
}
}
@@ -2106,7 +2106,7 @@
if (mConfig.isManualActive()) return mConfig.manualRule.zenMode;
int zen = Global.ZEN_MODE_OFF;
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
// automatic rule triggered dnd and user hasn't seen update dnd dialog
if (Settings.Secure.getInt(mContext.getContentResolver(),
@@ -2182,7 +2182,7 @@
}
for (ZenRule automaticRule : mConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
+ if (automaticRule.isActive()) {
// Active rules with INTERRUPTION_FILTER_ALL are not included in consolidated
// policy. This is relevant in case some other active rule has a more
// restrictive INTERRUPTION_FILTER but a more lenient ZenPolicy!
diff --git a/services/core/java/com/android/server/os/TEST_MAPPING b/services/core/java/com/android/server/os/TEST_MAPPING
index 50c8964..3ffcd18 100644
--- a/services/core/java/com/android/server/os/TEST_MAPPING
+++ b/services/core/java/com/android/server/os/TEST_MAPPING
@@ -2,36 +2,18 @@
"presubmit": [
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "BugreportManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "BugreportManagerTestCases_android_server_os"
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "CtsBugreportTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- }
- ]
+ "name": "CtsBugreportTestCases_android_server_os"
},
{
"name": "CtsUsbTests"
},
{
"file_patterns": ["Bugreport[^/]*\\.java"],
- "name": "ShellTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "ShellTests_android_server_os"
}
],
"postsubmit": [
diff --git a/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java b/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
index 4135161..5aea356 100644
--- a/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
+++ b/services/core/java/com/android/server/pm/BackgroundUserSoundNotifier.java
@@ -18,6 +18,7 @@
import static android.media.AudioAttributes.USAGE_ALARM;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Notification;
@@ -42,6 +43,8 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.List;
+
public class BackgroundUserSoundNotifier {
private static final boolean DEBUG = false;
@@ -49,11 +52,21 @@
private static final String BUSN_CHANNEL_ID = "bg_user_sound_channel";
private static final String BUSN_CHANNEL_NAME = "BackgroundUserSound";
public static final String ACTION_MUTE_SOUND = "com.android.server.ACTION_MUTE_BG_USER";
- private static final String EXTRA_NOTIFICATION_ID = "com.android.server.EXTRA_CLIENT_UID";
- private static final String EXTRA_CURRENT_USER_ID = "com.android.server.EXTRA_CURRENT_USER_ID";
private static final String ACTION_SWITCH_USER = "com.android.server.ACTION_SWITCH_TO_USER";
- /** ID of user with notification displayed, -1 if notification is not showing*/
- private int mUserWithNotification = -1;
+ private static final String ACTION_DISMISS_NOTIFICATION =
+ "com.android.server.ACTION_DISMISS_NOTIFICATION";
+ /**
+ * The clientUid from the AudioFocusInfo of the background user,
+ * for which an active notification is currently displayed.
+ * Set to -1 if no notification is being shown.
+ * TODO: b/367615180 - add support for multiple simultaneous alarms
+ */
+ @VisibleForTesting
+ int mNotificationClientUid = -1;
+ @VisibleForTesting
+ AudioPolicy mFocusControlAudioPolicy;
+ @VisibleForTesting
+ BackgroundUserListener mBgUserListener;
private final Context mSystemUserContext;
@VisibleForTesting
final NotificationManager mNotificationManager;
@@ -67,11 +80,18 @@
mSystemUserContext = context;
mNotificationManager = mSystemUserContext.getSystemService(NotificationManager.class);
mUserManager = mSystemUserContext.getSystemService(UserManager.class);
+ createNotificationChannel();
+ setupFocusControlAudioPolicy();
+ }
+
+ /**
+ * Creates a dedicated channel for background user related notifications.
+ */
+ private void createNotificationChannel() {
NotificationChannel channel = new NotificationChannel(BUSN_CHANNEL_ID, BUSN_CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH);
channel.setSound(null, null);
mNotificationManager.createNotificationChannel(channel);
- setupFocusControlAudioPolicy();
}
private void setupFocusControlAudioPolicy() {
@@ -81,15 +101,16 @@
ActivityManager am = mSystemUserContext.getSystemService(ActivityManager.class);
registerReceiver(am);
- BackgroundUserListener bgUserListener = new BackgroundUserListener(mSystemUserContext);
+ mBgUserListener = new BackgroundUserListener(mSystemUserContext);
AudioPolicy.Builder focusControlPolicyBuilder = new AudioPolicy.Builder(mSystemUserContext);
focusControlPolicyBuilder.setLooper(Looper.getMainLooper());
- focusControlPolicyBuilder.setAudioPolicyFocusListener(bgUserListener);
+ focusControlPolicyBuilder.setAudioPolicyFocusListener(mBgUserListener);
- AudioPolicy mFocusControlAudioPolicy = focusControlPolicyBuilder.build();
+ mFocusControlAudioPolicy = focusControlPolicyBuilder.build();
int status = mSystemUserContext.getSystemService(AudioManager.class)
.registerAudioPolicy(mFocusControlAudioPolicy);
+
if (status != AudioManager.SUCCESS) {
Log.w(LOG_TAG , "Could not register the service's focus"
+ " control audio policy, error: " + status);
@@ -117,123 +138,170 @@
@SuppressLint("MissingPermission")
public void onAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {
- BackgroundUserSoundNotifier.this.dismissNotificationIfNecessary(afi);
+ BackgroundUserSoundNotifier.this.dismissNotificationIfNecessary();
}
}
+ @VisibleForTesting
+ BackgroundUserListener getAudioPolicyFocusListener() {
+ return mBgUserListener;
+ }
+
/**
* Registers a BroadcastReceiver for actions related to background user sound notifications.
* When ACTION_MUTE_SOUND is received, it mutes a background user's alarm sound.
* When ACTION_SWITCH_USER is received, a switch to the background user with alarm is started.
*/
- private void registerReceiver(ActivityManager service) {
+ private void registerReceiver(ActivityManager activityManager) {
BroadcastReceiver backgroundUserNotificationBroadcastReceiver = new BroadcastReceiver() {
@SuppressLint("MissingPermission")
@Override
public void onReceive(Context context, Intent intent) {
- if (!(intent.hasExtra(EXTRA_NOTIFICATION_ID)
- && intent.hasExtra(EXTRA_CURRENT_USER_ID)
- && intent.hasExtra(Intent.EXTRA_USER_ID))) {
+ if (mNotificationClientUid == -1) {
return;
}
- final int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
+ dismissNotification();
if (DEBUG) {
- Log.d(LOG_TAG,
- "User with alarm id " + intent.getIntExtra(Intent.EXTRA_USER_ID,
- -1) + " current user id " + intent.getIntExtra(
- EXTRA_CURRENT_USER_ID, -1));
+ final int actionIndex = intent.getAction().lastIndexOf(".") + 1;
+ final String action = intent.getAction().substring(actionIndex);
+ Log.d(LOG_TAG, "Action requested: " + action + ", by userId "
+ + ActivityManager.getCurrentUser() + " for alarm on user "
+ + UserHandle.getUserHandleForUid(mNotificationClientUid));
}
- mUserWithNotification = -1;
- mNotificationManager.cancelAsUser(LOG_TAG, notificationId,
- UserHandle.of(intent.getIntExtra(EXTRA_CURRENT_USER_ID, -1)));
+
if (ACTION_MUTE_SOUND.equals(intent.getAction())) {
- final AudioManager audioManager =
- mSystemUserContext.getSystemService(AudioManager.class);
- if (audioManager != null) {
- for (AudioPlaybackConfiguration apc :
- audioManager.getActivePlaybackConfigurations()) {
- if (apc.getAudioAttributes().getUsage() == USAGE_ALARM) {
- if (apc.getPlayerProxy() != null) {
- apc.getPlayerProxy().stop();
- }
- }
- }
- }
+ muteAlarmSounds(mSystemUserContext);
} else if (ACTION_SWITCH_USER.equals(intent.getAction())) {
- service.switchUser(intent.getIntExtra(Intent.EXTRA_USER_ID, -1));
+ activityManager.switchUser(UserHandle.getUserId(mNotificationClientUid));
}
+
+ mNotificationClientUid = -1;
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_MUTE_SOUND);
filter.addAction(ACTION_SWITCH_USER);
+ filter.addAction(ACTION_DISMISS_NOTIFICATION);
mSystemUserContext.registerReceiver(backgroundUserNotificationBroadcastReceiver, filter,
Context.RECEIVER_NOT_EXPORTED);
}
/**
+ * Stop player proxy for the ongoing alarm and drop focus for its AudioFocusInfo.
+ */
+ @VisibleForTesting
+ void muteAlarmSounds(Context context) {
+ AudioManager audioManager = context.getSystemService(AudioManager.class);
+ if (audioManager != null) {
+ for (AudioPlaybackConfiguration apc : audioManager.getActivePlaybackConfigurations()) {
+ if (apc.getClientUid() == mNotificationClientUid && apc.getPlayerProxy() != null) {
+ apc.getPlayerProxy().stop();
+ }
+ }
+ }
+ }
+
+ /**
* Check if sound is coming from background user and show notification is required.
*/
@VisibleForTesting
- void notifyForegroundUserAboutSoundIfNecessary(AudioFocusInfo afi, Context
- foregroundContext) throws RemoteException {
+ void notifyForegroundUserAboutSoundIfNecessary(AudioFocusInfo afi, Context foregroundContext)
+ throws RemoteException {
final int userId = UserHandle.getUserId(afi.getClientUid());
final int usage = afi.getAttributes().getUsage();
UserInfo userInfo = mUserManager.getUserInfo(userId);
- if (userInfo != null && userId != foregroundContext.getUserId()) {
+ // Only show notification if the sound is coming from background user and the notification
+ // is not already shown.
+ if (userInfo != null && userId != foregroundContext.getUserId()
+ && mNotificationClientUid == -1) {
//TODO: b/349138482 - Add handling of cases when usage == USAGE_NOTIFICATION_RINGTONE
if (usage == USAGE_ALARM) {
- Intent muteIntent = createIntent(ACTION_MUTE_SOUND, afi, foregroundContext, userId);
- PendingIntent mutePI = PendingIntent.getBroadcast(mSystemUserContext, 0,
- muteIntent, PendingIntent.FLAG_UPDATE_CURRENT
- | PendingIntent.FLAG_IMMUTABLE);
- Intent switchIntent = createIntent(ACTION_SWITCH_USER, afi, foregroundContext,
- userId);
- PendingIntent switchPI = PendingIntent.getBroadcast(mSystemUserContext, 0,
- switchIntent, PendingIntent.FLAG_UPDATE_CURRENT
- | PendingIntent.FLAG_IMMUTABLE);
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Alarm ringing on background user " + userId
+ + ", displaying notification for current user "
+ + foregroundContext.getUserId());
+ }
- mUserWithNotification = foregroundContext.getUserId();
- mNotificationManager.notifyAsUser(LOG_TAG, afi.getClientUid(),
- createNotification(userInfo.name, mutePI, switchPI, foregroundContext),
+ mNotificationClientUid = afi.getClientUid();
+
+ mNotificationManager.notifyAsUser(LOG_TAG, mNotificationClientUid,
+ createNotification(userInfo.name, foregroundContext),
foregroundContext.getUser());
}
}
}
/**
- * If notification is present, dismisses it. To be called when the relevant sound loses focus.
+ * Dismisses notification if the associated focus has been removed from the focus stack.
+ * Notification remains if the focus is temporarily lost due to another client taking over the
+ * focus ownership.
*/
- private void dismissNotificationIfNecessary(AudioFocusInfo afi) {
- if (mUserWithNotification >= 0) {
- mNotificationManager.cancelAsUser(LOG_TAG, afi.getClientUid(),
- UserHandle.of(mUserWithNotification));
+ @VisibleForTesting
+ void dismissNotificationIfNecessary() {
+ if (getAudioFocusInfoForNotification() == null && mNotificationClientUid >= 0) {
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Alarm ringing on background user "
+ + UserHandle.getUserHandleForUid(mNotificationClientUid).getIdentifier()
+ + " left focus stack, dismissing notification");
+ }
+ dismissNotification();
+ mNotificationClientUid = -1;
}
- mUserWithNotification = -1;
}
- private Intent createIntent(String intentAction, AudioFocusInfo afi, Context fgUserContext,
- int userId) {
+ /**
+ * Dismisses notification for all users in case user switch occurred after notification was
+ * shown.
+ */
+ @SuppressLint("MissingPermission")
+ private void dismissNotification() {
+ mNotificationManager.cancelAsUser(LOG_TAG, mNotificationClientUid, UserHandle.ALL);
+ }
+
+ /**
+ * Returns AudioFocusInfo associated with the current notification.
+ */
+ @SuppressLint("MissingPermission")
+ @VisibleForTesting
+ @Nullable
+ AudioFocusInfo getAudioFocusInfoForNotification() {
+ if (mNotificationClientUid >= 0) {
+ List<AudioFocusInfo> stack = mFocusControlAudioPolicy.getFocusStack();
+ for (int i = stack.size() - 1; i >= 0; i--) {
+ if (stack.get(i).getClientUid() == mNotificationClientUid) {
+ return stack.get(i);
+ }
+ }
+ }
+ return null;
+ }
+
+ private PendingIntent createPendingIntent(String intentAction) {
final Intent intent = new Intent(intentAction);
- intent.putExtra(EXTRA_CURRENT_USER_ID, fgUserContext.getUserId());
- intent.putExtra(EXTRA_NOTIFICATION_ID, afi.getClientUid());
- intent.putExtra(Intent.EXTRA_USER_ID, userId);
- return intent;
+ PendingIntent resultPI = PendingIntent.getBroadcast(mSystemUserContext, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ return resultPI;
}
- private Notification createNotification(String userName, PendingIntent muteIntent,
- PendingIntent switchIntent, Context fgContext) {
+ @VisibleForTesting
+ Notification createNotification(String userName, Context fgContext) {
final String title = fgContext.getString(R.string.bg_user_sound_notification_title_alarm,
userName);
final int icon = R.drawable.ic_audio_alarm;
+
+ PendingIntent mutePI = createPendingIntent(ACTION_MUTE_SOUND);
+ PendingIntent switchPI = createPendingIntent(ACTION_SWITCH_USER);
+ PendingIntent dismissNotificationPI = createPendingIntent(ACTION_DISMISS_NOTIFICATION);
+
final Notification.Action mute = new Notification.Action.Builder(null,
fgContext.getString(R.string.bg_user_sound_notification_button_mute),
- muteIntent).build();
+ mutePI).build();
final Notification.Action switchUser = new Notification.Action.Builder(null,
fgContext.getString(R.string.bg_user_sound_notification_button_switch_user),
- switchIntent).build();
+ switchPI).build();
+
Notification.Builder notificationBuilder = new Notification.Builder(mSystemUserContext,
BUSN_CHANNEL_ID)
.setSmallIcon(icon)
@@ -243,16 +311,18 @@
.setOngoing(true)
.setColor(fgContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
- .setContentIntent(muteIntent)
+ .setContentIntent(mutePI)
.setAutoCancel(true)
+ .setDeleteIntent(dismissNotificationPI)
.setVisibility(Notification.VISIBILITY_PUBLIC);
+
if (mUserManager.isUserSwitcherEnabled() && (mUserManager.getUserSwitchability(
- UserHandle.of(fgContext.getUserId())) == UserManager.SWITCHABILITY_STATUS_OK)) {
+ fgContext.getUser()) == UserManager.SWITCHABILITY_STATUS_OK)) {
notificationBuilder.setActions(mute, switchUser);
} else {
notificationBuilder.setActions(mute);
}
+
return notificationBuilder.build();
}
}
-
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index ee15bec..efd58ed 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -92,7 +92,6 @@
import android.multiuser.Flags;
import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IInterface;
@@ -215,7 +214,7 @@
@VisibleForTesting
static class LauncherAppsImpl extends ILauncherApps.Stub {
- private static final boolean DEBUG = Build.IS_DEBUGGABLE;
+ private static final boolean DEBUG = false;
private static final String TAG = "LauncherAppsService";
private static final String NAMESPACE_MULTIUSER = "multiuser";
private static final String FLAG_NON_SYSTEM_ACCESS_TO_HIDDEN_PROFILES =
@@ -496,28 +495,8 @@
private boolean canAccessProfile(int callingUid, int callingUserId, int callingPid,
int targetUserId, String message) {
- if (DEBUG) {
- final AndroidPackage callingPackage =
- mPackageManagerInternal.getPackage(callingUid);
- final String callingPackageName = callingPackage == null
- ? null : callingPackage.getPackageName();
- Slog.v(TAG, "canAccessProfile called by " + callingPackageName
- + " for user " + callingUserId
- + " requesting to access user "
- + targetUserId + " when invoking " + message);
- }
- if (targetUserId == callingUserId) {
- if (DEBUG) {
- Slog.v(TAG, message + " passed canAccessProfile for targetuser"
- + targetUserId + " because it is the same as the calling user");
- }
- return true;
- }
+ if (targetUserId == callingUserId) return true;
if (injectHasInteractAcrossUsersFullPermission(callingPid, callingUid)) {
- if (DEBUG) {
- Slog.v(TAG, message + " passed because calling process"
- + "has permission to interact across users");
- }
return true;
}
@@ -535,25 +514,11 @@
if (isHiddenProfile(UserHandle.of(targetUserId))
&& !canAccessHiddenProfile(callingUid, callingPid)) {
- Slog.w(TAG, message + " for hidden profile user " + targetUserId
- + " from " + callingUserId + " not allowed");
-
return false;
}
- final boolean ret = mUserManagerInternal.isProfileAccessible(
- callingUserId, targetUserId, message, true);
- if (DEBUG) {
- final AndroidPackage callingPackage =
- mPackageManagerInternal.getPackage(callingUid);
- final String callingPackageName = callingPackage == null
- ? null : callingPackage.getPackageName();
- Slog.v(TAG, "canAccessProfile returned " + ret + " for " + callingPackageName
- + " for user " + callingUserId
- + " requesting to access user "
- + targetUserId + " when invoking " + message);
- }
- return ret;
+ return mUserManagerInternal.isProfileAccessible(callingUserId, targetUserId,
+ message, true);
}
private boolean isHiddenProfile(UserHandle targetUser) {
@@ -1376,10 +1341,6 @@
@Override
public void pinShortcuts(String callingPackage, String packageName, List<String> ids,
UserHandle targetUser) {
- if (DEBUG) {
- Slog.v(TAG, "pinShortcuts: " + callingPackage + " is pinning shortcuts from "
- + packageName + " for user " + targetUser);
- }
if (!mShortcutServiceInternal
.areShortcutsSupportedOnHomeScreen(targetUser.getIdentifier())) {
// Requires strict ACCESS_SHORTCUTS permission for user-profiles with items
@@ -1390,11 +1351,6 @@
}
ensureShortcutPermission(callingPackage);
if (!canAccessProfile(targetUser.getIdentifier(), "Cannot pin shortcuts")) {
- if (DEBUG) {
- Slog.v(TAG, "pinShortcuts: " + callingPackage
- + " is pinning shortcuts from " + packageName
- + " for user " + targetUser + " but cannot access profile");
- }
return;
}
@@ -2451,7 +2407,7 @@
final int callbackUserId = callbackUser.getIdentifier();
final int shortcutUserId = shortcutUser.getIdentifier();
- if (shortcutUser == callbackUser) return true;
+ if ((shortcutUser.equals(callbackUser))) return true;
return mUserManagerInternal.isProfileAccessible(callbackUserId, shortcutUserId,
null, false);
}
@@ -2485,16 +2441,28 @@
final BroadcastCookie cookie =
(BroadcastCookie) mListeners.getBroadcastCookie(i);
if (!isEnabledProfileOf(cookie, user, "onPackageRemoved")) {
+ // b/350144057
+ Slog.d(TAG, "onPackageRemoved: Skipping - profile not enabled"
+ + " or not accessible for user=" + user
+ + ", packageName=" + packageName);
continue;
}
if (!isCallingAppIdAllowed(appIdAllowList, UserHandle.getAppId(
cookie.callingUid))) {
+ // b/350144057
+ Slog.d(TAG, "onPackageRemoved: Skipping - appId not allowed"
+ + " for user=" + user
+ + ", packageName=" + packageName);
continue;
}
try {
+ // b/350144057
+ Slog.d(TAG, "onPackageRemoved: triggering onPackageRemoved"
+ + " for user=" + user
+ + ", packageName=" + packageName);
listener.onPackageRemoved(user, packageName);
} catch (RemoteException re) {
- Slog.d(TAG, "Callback failed ", re);
+ Slog.d(TAG, "onPackageRemoved: Callback failed ", re);
}
}
} finally {
@@ -2524,15 +2492,27 @@
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
if (!isEnabledProfileOf(cookie, user, "onPackageAdded")) {
+ // b/350144057
+ Slog.d(TAG, "onPackageAdded: Skipping - profile not enabled"
+ + " or not accessible for user=" + user
+ + ", packageName=" + packageName);
continue;
}
if (!isPackageVisibleToListener(packageName, cookie, user)) {
+ // b/350144057
+ Slog.d(TAG, "onPackageAdded: Skipping - package filtered"
+ + " for user=" + user
+ + ", packageName=" + packageName);
continue;
}
try {
+ // b/350144057
+ Slog.d(TAG, "onPackageAdded: triggering onPackageAdded"
+ + " for user=" + user
+ + ", packageName=" + packageName);
listener.onPackageAdded(user, packageName);
} catch (RemoteException re) {
- Slog.d(TAG, "Callback failed ", re);
+ Slog.d(TAG, "onPackageAdded: Callback failed ", re);
}
}
} finally {
@@ -2566,7 +2546,7 @@
try {
listener.onPackageChanged(user, packageName);
} catch (RemoteException re) {
- Slog.d(TAG, "Callback failed ", re);
+ Slog.d(TAG, "onPackageChanged: Callback failed ", re);
}
}
} finally {
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index d65e30b..045d4db 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -42,7 +42,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
/**
* Launcher information used by {@link ShortcutService}.
@@ -129,15 +128,9 @@
*/
public void pinShortcuts(@UserIdInt int packageUserId,
@NonNull String packageName, @NonNull List<String> ids, boolean forPinRequest) {
- if (ShortcutService.DEBUG) {
- Slog.v(TAG, "ShortcutLauncher#pinShortcuts: pin shortcuts from " + packageName
- + " with userId=" + packageUserId + " shortcutIds="
- + ids.stream().collect(Collectors.joining(", ", "[", "]")));
- }
final ShortcutPackage packageShortcuts =
mShortcutUser.getPackageShortcutsIfExists(packageName);
if (packageShortcuts == null) {
- Slog.w(TAG, "ShortcutLauncher#pinShortcuts packageShortcuts is null");
return; // No need to instantiate.
}
@@ -162,10 +155,6 @@
final String id = ids.get(i);
final ShortcutInfo si = packageShortcuts.findShortcutById(id);
if (si == null) {
- if (ShortcutService.DEBUG) {
- Slog.w(TAG, "ShortcutLauncher#pinShortcuts: cannot pin "
- + id + " because it does not exist");
- }
continue;
}
if (si.isDynamic() || si.isLongLived()
@@ -185,13 +174,6 @@
}
}
}
- if (ShortcutService.DEBUG) {
- Slog.v(TAG, "ShortcutLauncher#pinShortcuts: "
- + " newSet: " + newSet.stream().collect(
- Collectors.joining(", ", "[", "]"))
- + " floatingSet: " + floatingSet.stream().collect(
- Collectors.joining(", ", "[", "]")));
- }
mPinnedShortcuts.put(up, newSet);
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index c9ad498..60056eb 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -729,11 +729,6 @@
}
pinnedShortcuts.addAll(pinned);
});
- if (ShortcutService.DEBUG) {
- Slog.v(TAG, "ShortcutPackage#refreshPinnedFlags: "
- + " pinnedShortcuts: " + pinnedShortcuts.stream().collect(
- Collectors.joining(", ", "[", "]")));
- }
// Secondly, update the pinned state if necessary.
final List<ShortcutInfo> pinned = findAll(pinnedShortcuts);
if (pinned != null) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index ea495c9..a3ff195 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -169,7 +169,7 @@
public class ShortcutService extends IShortcutService.Stub {
static final String TAG = "ShortcutService";
- static final boolean DEBUG = Build.IS_DEBUGGABLE; // STOPSHIP if true
+ static final boolean DEBUG = false; // STOPSHIP if true
static final boolean DEBUG_LOAD = false; // STOPSHIP if true
static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true
static final boolean DEBUG_REBOOT = Build.IS_DEBUGGABLE;
@@ -3206,11 +3206,6 @@
public void pinShortcuts(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
@NonNull List<String> shortcutIds, int userId) {
- if (DEBUG) {
- Slog.v(TAG, "pinShortcuts: " + callingPackage + ", with userId=" + launcherUserId
- + ", is trying to pin shortcuts from " + packageName
- + " with userId=" + userId);
- }
// Calling permission must be checked by LauncherAppsImpl.
Preconditions.checkStringNotEmpty(packageName, "packageName");
Objects.requireNonNull(shortcutIds, "shortcutIds");
@@ -3235,11 +3230,6 @@
&& !si.isDeclaredInManifest(),
ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO,
callingPackage, launcherUserId, false);
- } else {
- if (DEBUG) {
- Slog.w(TAG, "specified package " + packageName + ", with userId=" + userId
- + ", doesn't exist.");
- }
}
// Get list of shortcuts that will get unpinned.
ArraySet<String> oldPinnedIds = launcher.getPinnedShortcutIds(packageName, userId);
@@ -5458,17 +5448,6 @@
*/
private List<ShortcutInfo> prepareChangedShortcuts(ArraySet<String> changedIds,
ArraySet<String> newIds, List<ShortcutInfo> deletedList, final ShortcutPackage ps) {
- if (DEBUG) {
- Slog.v(TAG, "prepareChangedShortcuts: "
- + " changedIds=" + (changedIds == null
- ? "n/a" : changedIds.stream().collect(Collectors.joining(", ", "[", "]")))
- + " newIds=" + (newIds == null
- ? "n/a" : newIds.stream().collect(Collectors.joining(", ", "[", "]")))
- + " deletedList=" + (deletedList == null
- ? "n/a" : deletedList.stream().map(ShortcutInfo::getId).collect(
- Collectors.joining(", ", "[", "]")))
- + " ps=" + (ps == null ? "n/a" : ps.getPackageName()));
- }
if (ps == null) {
// This can happen when package restore is not finished yet.
return null;
diff --git a/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING b/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
index 8a1982a..db98c40 100644
--- a/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "PackageManagerServiceUnitTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.test.verify.domain"
- }
- ]
+ "name": "PackageManagerServiceUnitTests_verify_domain"
},
{
"name": "CtsDomainVerificationDeviceStandaloneTestCases"
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ed9dcfa..ef37464 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -83,6 +83,7 @@
import static com.android.hardware.input.Flags.emojiAndScreenshotKeycodesAvailable;
import static com.android.hardware.input.Flags.modifierShortcutDump;
+import static com.android.hardware.input.Flags.useKeyGestureEventHandler;
import static com.android.server.flags.Flags.modifierShortcutManagerMultiuser;
import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
@@ -809,7 +810,7 @@
event.recycle();
break;
case MSG_HANDLE_ALL_APPS:
- launchAllAppsAction((KeyEvent) msg.obj);
+ launchAllAppsAction();
break;
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
@@ -820,7 +821,7 @@
case MSG_SWITCH_KEYBOARD_LAYOUT:
SwitchKeyboardLayoutMessageObject object =
(SwitchKeyboardLayoutMessageObject) msg.obj;
- handleSwitchKeyboardLayout(object.keyEvent, object.direction,
+ handleSwitchKeyboardLayout(object.displayId, object.direction,
object.focusedToken);
break;
case MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE:
@@ -937,7 +938,7 @@
}
}
- private record SwitchKeyboardLayoutMessageObject(KeyEvent keyEvent, IBinder focusedToken,
+ private record SwitchKeyboardLayoutMessageObject(int displayId, IBinder focusedToken,
int direction) {
}
@@ -1813,9 +1814,7 @@
Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
}
- private void handleShortPressOnHome(KeyEvent event) {
- notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_HOME);
-
+ private void handleShortPressOnHome(int displayId) {
// Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
final HdmiControl hdmiControl = getHdmiControl();
if (hdmiControl != null) {
@@ -1831,7 +1830,7 @@
}
// Go home!
- launchHomeFromHotKey(event.getDisplayId());
+ launchHomeFromHotKey(displayId);
}
/**
@@ -1878,11 +1877,9 @@
}
}
- private void launchAllAppsAction(KeyEvent event) {
+ private void launchAllAppsAction() {
if (mHasFeatureLeanback || mHasFeatureWatch) {
// TV and watch support the all apps intent
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS);
Intent intent = new Intent(Intent.ACTION_ALL_APPS);
if (mHasFeatureLeanback) {
Intent intentLauncher = new Intent(Intent.ACTION_MAIN);
@@ -1896,8 +1893,6 @@
}
startActivityAsUser(intent, UserHandle.CURRENT);
} else {
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS);
AccessibilityManagerInternal accessibilityManager = getAccessibilityManagerInternal();
if (accessibilityManager != null) {
accessibilityManager.performSystemAction(
@@ -1949,7 +1944,9 @@
@Override
public void run() {
if (mPendingHomeKeyEvent != null) {
- handleShortPressOnHome(mPendingHomeKeyEvent);
+ notifyKeyGestureCompleted(mPendingHomeKeyEvent,
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME);
+ handleShortPressOnHome(mPendingHomeKeyEvent.getDisplayId());
mPendingHomeKeyEvent = null;
}
}
@@ -2002,7 +1999,10 @@
}
// Post to main thread to avoid blocking input pipeline.
- mHandler.post(() -> handleShortPressOnHome(event));
+ mHandler.post(() -> {
+ notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_HOME);
+ handleShortPressOnHome(event.getDisplayId());
+ });
return true;
}
@@ -2080,7 +2080,8 @@
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, "Home - Long Press");
switch (mLongPressOnHomeBehavior) {
case LONG_PRESS_HOME_ALL_APPS:
- launchAllAppsAction(event);
+ notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS);
+ launchAllAppsAction();
break;
case LONG_PRESS_HOME_ASSIST:
notifyKeyGestureCompleted(event,
@@ -2430,6 +2431,7 @@
mWindowWakeUpPolicy = injector.getWindowWakeUpPolicy();
initKeyCombinationRules();
initSingleKeyGestureRules(injector.getLooper());
+ initKeyGestures();
mButtonOverridePermissionChecker = injector.getButtonOverridePermissionChecker();
mSideFpsEventHandler = new SideFpsEventHandler(mContext, mHandler, mPowerManager);
}
@@ -3354,12 +3356,6 @@
mConsumedKeysForDevice.put(deviceId, consumedKeys);
}
- // TODO(b/358569822) Remove below once we have nicer API for listening to shortcuts
- if ((event.isMetaPressed() || KeyEvent.isMetaKey(keyCode))
- && shouldInterceptShortcuts(focusedToken)) {
- return keyNotConsumed;
- }
-
if (interceptSystemKeysAndShortcuts(focusedToken, event)
&& event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
consumedKeys.add(keyCode);
@@ -3388,6 +3384,10 @@
// conflicting events to application, make sure to consume the event on
// ACTION_DOWN even if you want to do something on ACTION_UP. This is essential
// to maintain event parity and to not have incomplete key gestures.
+ //
+ // NOTE: Please try not to add new Shortcut combinations here and instead use KeyGestureEvents.
+ // Add shortcut trigger logic in {@code KeyGestureController} and add handling logic in
+ // {@link handleKeyGesture()}
@SuppressLint("MissingPermission")
private boolean interceptSystemKeysAndShortcuts(IBinder focusedToken, KeyEvent event) {
final boolean keyguardOn = keyguardOn();
@@ -3516,6 +3516,7 @@
injectBackGesture(event.getDownTime());
return true;
}
+ break;
case KeyEvent.KEYCODE_DPAD_UP:
if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
@@ -3544,11 +3545,11 @@
moveFocusedTaskToStageSplit(getTargetDisplayIdForKeyEvent(event),
true /* leftOrTop */);
notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION);
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT);
} else if (event.isAltPressed()) {
setSplitscreenFocus(true /* leftOrTop */);
notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS);
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT);
} else {
notifyKeyGestureCompleted(event,
KeyGestureEvent.KEY_GESTURE_TYPE_BACK);
@@ -3563,12 +3564,12 @@
moveFocusedTaskToStageSplit(getTargetDisplayIdForKeyEvent(event),
false /* leftOrTop */);
notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION);
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT);
return true;
} else if (event.isAltPressed()) {
setSplitscreenFocus(false /* leftOrTop */);
notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS);
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT);
return true;
}
}
@@ -3593,30 +3594,7 @@
if (down) {
int direction = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_UP ? 1 : -1;
- int screenDisplayId = displayId < 0 ? DEFAULT_DISPLAY : displayId;
-
- float minLinearBrightness = mPowerManager.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
- float maxLinearBrightness = mPowerManager.getBrightnessConstraint(
- PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
- float linearBrightness = mDisplayManager.getBrightness(screenDisplayId);
-
- float gammaBrightness = BrightnessUtils.convertLinearToGamma(linearBrightness);
- float adjustedGammaBrightness =
- gammaBrightness + 1f / BRIGHTNESS_STEPS * direction;
- adjustedGammaBrightness = MathUtils.constrain(adjustedGammaBrightness, 0f,
- 1f);
- float adjustedLinearBrightness = BrightnessUtils.convertGammaToLinear(
- adjustedGammaBrightness);
- adjustedLinearBrightness = MathUtils.constrain(adjustedLinearBrightness,
- minLinearBrightness, maxLinearBrightness);
- mDisplayManager.setBrightness(screenDisplayId, adjustedLinearBrightness);
-
- Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
- intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION
- | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
- intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true);
- startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ changeDisplayBrightnessValue(displayId, direction);
int gestureType = keyCode == KeyEvent.KEYCODE_BRIGHTNESS_DOWN
? KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN
@@ -3689,10 +3667,11 @@
case KeyEvent.KEYCODE_ALL_APPS:
if (firstDown) {
mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
-
Message msg = mHandler.obtainMessage(MSG_HANDLE_ALL_APPS, new KeyEvent(event));
msg.setAsynchronous(true);
msg.sendToTarget();
+
+ notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS);
}
return true;
case KeyEvent.KEYCODE_NOTIFICATION:
@@ -3720,7 +3699,7 @@
case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
if (firstDown) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
- sendSwitchKeyboardLayout(event, focusedToken, direction);
+ sendSwitchKeyboardLayout(displayId, focusedToken, direction);
notifyKeyGestureCompleted(event,
KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH);
return true;
@@ -3745,7 +3724,9 @@
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK);
} else if (mPendingMetaAction) {
if (!canceled) {
- launchAllAppsAction(event);
+ launchAllAppsAction();
+ notifyKeyGestureCompleted(event,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS);
}
mPendingMetaAction = false;
}
@@ -3829,13 +3810,252 @@
return (metaState & KeyEvent.META_META_ON) != 0;
}
- private boolean shouldInterceptShortcuts(IBinder focusedToken) {
- KeyInterceptionInfo info =
- mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken);
- boolean hasInterceptWindowFlag = (info.layoutParamsPrivateFlags
- & WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) != 0;
- return hasInterceptWindowFlag && mButtonOverridePermissionChecker.canAppOverrideSystemKey(
- mContext, info.windowOwnerUid);
+ @SuppressLint("MissingPermission")
+ private void initKeyGestures() {
+ if (!useKeyGestureEventHandler()) {
+ return;
+ }
+ mInputManager.registerKeyGestureEventHandler(new InputManager.KeyGestureEventHandler() {
+ @Override
+ public boolean handleKeyGestureEvent(@NonNull KeyGestureEvent event,
+ @Nullable IBinder focusedToken) {
+ return PhoneWindowManager.this.handleKeyGestureEvent(event, focusedToken);
+ }
+
+ @Override
+ public boolean isKeyGestureSupported(int gestureType) {
+ switch (gestureType) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_HOME:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_BACK:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
+ return true;
+ default:
+ return false;
+ }
+ }
+ });
+ }
+
+ @VisibleForTesting
+ boolean handleKeyGestureEvent(KeyGestureEvent event, IBinder focusedToken) {
+ boolean start = event.getAction() == KeyGestureEvent.ACTION_GESTURE_START;
+ boolean complete = event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ && !event.isCancelled();
+ int deviceId = event.getDeviceId();
+ int gestureType = event.getKeyGestureType();
+ int displayId = event.getDisplayId();
+ int modifierState = event.getModifierState();
+ boolean keyguardOn = keyguardOn();
+ switch (gestureType) {
+ case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS:
+ if (complete) {
+ showRecentApps(false);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH:
+ if (!keyguardOn) {
+ if (start) {
+ preloadRecentApps();
+ } else if (complete) {
+ toggleRecentApps();
+ }
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT:
+ if (complete) {
+ launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
+ deviceId, SystemClock.uptimeMillis(),
+ AssistUtils.INVOCATION_TYPE_UNKNOWN);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_HOME:
+ if (complete) {
+ // Post to main thread to avoid blocking input pipeline.
+ mHandler.post(() -> handleShortPressOnHome(displayId));
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS:
+ if (complete) {
+ showSystemSettings();
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN:
+ if (complete) {
+ lockNow(null /* options */);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL:
+ if (complete) {
+ toggleNotificationPanel();
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT:
+ if (complete) {
+ interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT:
+ if (complete && mEnableBugReportKeyboardShortcut) {
+ try {
+ mActivityManagerService.requestInteractiveBugReport();
+ } catch (RemoteException e) {
+ Slog.d(TAG, "Error taking bugreport", e);
+ }
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_BACK:
+ if (complete) {
+ injectBackGesture(SystemClock.uptimeMillis());
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION:
+ if (complete) {
+ StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
+ if (statusbar != null) {
+ statusbar.moveFocusedTaskToFullscreen(
+ getTargetDisplayIdForKeyGestureEvent(event));
+ }
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE:
+ if (complete) {
+ StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
+ if (statusbar != null) {
+ statusbar.moveFocusedTaskToDesktop(
+ getTargetDisplayIdForKeyGestureEvent(event));
+ }
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT:
+ if (complete) {
+ moveFocusedTaskToStageSplit(getTargetDisplayIdForKeyGestureEvent(event),
+ true /* leftOrTop */);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT:
+ if (complete) {
+ setSplitscreenFocus(true /* leftOrTop */);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT:
+ if (complete) {
+ moveFocusedTaskToStageSplit(getTargetDisplayIdForKeyGestureEvent(event),
+ false /* leftOrTop */);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT:
+ if (complete) {
+ setSplitscreenFocus(false /* leftOrTop */);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER:
+ if (complete) {
+ toggleKeyboardShortcutsMenu(deviceId);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN:
+ if (complete) {
+ int direction =
+ gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP ? 1 : -1;
+ changeDisplayBrightnessValue(displayId, direction);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER:
+ if (start) {
+ showRecentApps(true);
+ } else {
+ hideRecentApps(true, false);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS:
+ case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
+ if (complete) {
+ launchAllAppsAction();
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH:
+ if (complete) {
+ launchTargetSearchActivity();
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH:
+ if (complete) {
+ int direction = (modifierState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
+ sendSwitchKeyboardLayout(displayId, focusedToken, direction);
+ }
+ return true;
+ // TODO (b/358569822): Move these input specific gesture handling to IMS since we
+ // are calling into InputManager through internal API anyways
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP:
+ if (complete) {
+ mInputManagerInternal.incrementKeyboardBacklight(deviceId);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN:
+ if (complete) {
+ mInputManagerInternal.decrementKeyboardBacklight(deviceId);
+ }
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE:
+ return true;
+ case KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK:
+ if (complete) {
+ mInputManagerInternal.toggleCapsLock(deviceId);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void changeDisplayBrightnessValue(int displayId, int direction) {
+ int screenDisplayId = displayId < 0 ? DEFAULT_DISPLAY : displayId;
+
+ float minLinearBrightness = mPowerManager.getBrightnessConstraint(
+ PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
+ float maxLinearBrightness = mPowerManager.getBrightnessConstraint(
+ PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM);
+ float linearBrightness = mDisplayManager.getBrightness(screenDisplayId);
+
+ float gammaBrightness = BrightnessUtils.convertLinearToGamma(linearBrightness);
+ float adjustedGammaBrightness = gammaBrightness + 1f / BRIGHTNESS_STEPS * direction;
+ adjustedGammaBrightness = MathUtils.constrain(adjustedGammaBrightness, 0f, 1f);
+ float adjustedLinearBrightness = BrightnessUtils.convertGammaToLinear(
+ adjustedGammaBrightness);
+ adjustedLinearBrightness = MathUtils.constrain(adjustedLinearBrightness,
+ minLinearBrightness, maxLinearBrightness);
+ mDisplayManager.setBrightness(screenDisplayId, adjustedLinearBrightness);
+
+ Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION
+ | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
+ intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true);
+ startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
}
/**
@@ -4081,7 +4301,7 @@
if (KeyEvent.metaStateHasModifiers(metaState & ~KeyEvent.META_SHIFT_MASK,
KeyEvent.META_CTRL_ON)) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
- sendSwitchKeyboardLayout(event, focusedToken, direction);
+ sendSwitchKeyboardLayout(event.getDisplayId(), focusedToken, direction);
return true;
}
}
@@ -4139,19 +4359,18 @@
}
}
- private void sendSwitchKeyboardLayout(@NonNull KeyEvent event,
- @Nullable IBinder focusedToken, int direction) {
+ private void sendSwitchKeyboardLayout(int displayId, @Nullable IBinder focusedToken,
+ int direction) {
SwitchKeyboardLayoutMessageObject object =
- new SwitchKeyboardLayoutMessageObject(event, focusedToken, direction);
+ new SwitchKeyboardLayoutMessageObject(displayId, focusedToken, direction);
mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, object).sendToTarget();
}
- private void handleSwitchKeyboardLayout(@NonNull KeyEvent event, int direction,
- IBinder focusedToken) {
+ private void handleSwitchKeyboardLayout(int displayId, int direction, IBinder focusedToken) {
IBinder targetWindowToken =
mWindowManagerInternal.getTargetWindowTokenFromInputToken(focusedToken);
- InputMethodManagerInternal.get().onSwitchKeyboardLayoutShortcut(direction,
- event.getDisplayId(), targetWindowToken);
+ InputMethodManagerInternal.get().onSwitchKeyboardLayoutShortcut(direction, displayId,
+ targetWindowToken);
}
private boolean interceptFallback(IBinder focusedToken, KeyEvent fallbackEvent,
@@ -7000,16 +7219,22 @@
}
private int getTargetDisplayIdForKeyEvent(KeyEvent event) {
- int displayId = event.getDisplayId();
-
- if (displayId == INVALID_DISPLAY) {
- displayId = mTopFocusedDisplayId;
+ if (event.getDisplayId() != INVALID_DISPLAY) {
+ return event.getDisplayId();
}
-
- if (displayId == INVALID_DISPLAY) {
- return DEFAULT_DISPLAY;
- } else {
- return displayId;
+ if (mTopFocusedDisplayId != INVALID_DISPLAY) {
+ return mTopFocusedDisplayId;
}
+ return DEFAULT_DISPLAY;
+ }
+
+ private int getTargetDisplayIdForKeyGestureEvent(KeyGestureEvent event) {
+ if (event.getDisplayId() != INVALID_DISPLAY) {
+ return event.getDisplayId();
+ }
+ if (mTopFocusedDisplayId != INVALID_DISPLAY) {
+ return mTopFocusedDisplayId;
+ }
+ return DEFAULT_DISPLAY;
}
}
diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING
index bdb174d..76a0503 100644
--- a/services/core/java/com/android/server/policy/TEST_MAPPING
+++ b/services/core/java/com/android/server/policy/TEST_MAPPING
@@ -1,32 +1,10 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.policy."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksServicesTests_android_server_policy_Presubmit"
},
{
- "name": "WmTests",
- "options": [
- {
- "include-filter": "com.android.server.policy."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "WmTests_server_policy_Presubmit"
},
{
"name": "CtsPermissionPolicyTestCases",
@@ -49,30 +27,15 @@
"name": "CtsPermissionTestCases_Platform"
},
{
- "name": "CtsBackupTestCases",
- "options": [
- {
- "include-filter": "android.backup.cts.PermissionTest"
- }
- ]
+ "name": "CtsBackupTestCases_cts_permissiontest"
}
],
"postsubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.policy."
- }
- ]
+ "name": "FrameworksServicesTests_android_server_policy"
},
{
- "name": "WmTests",
- "options": [
- {
- "include-filter": "com.android.server.policy."
- }
- ]
+ "name": "WmTests_server_policy"
},
{
"name": "CtsPermissionPolicyTestCases",
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
index 935a238..f67f56d 100644
--- a/services/core/java/com/android/server/power/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -1,22 +1,13 @@
{
"presubmit": [
{
- "name": "CtsBatterySavingTestCases",
- "options": [
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"}
- ]
+ "name": "CtsBatterySavingTestCases_android_server_power"
},
{
"name": "FrameworksMockingServicesTests_android_server_power_Presubmit"
},
{
- "name": "PowerServiceTests",
- "options": [
- {"include-filter": "com.android.server.power"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "PowerServiceTests_server_power"
}
],
"postsubmit": [
@@ -24,28 +15,16 @@
"name": "CtsBatterySavingTestCases"
},
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server.power"}
- ]
+ "name": "FrameworksMockingServicesTests_android_server_power"
},
{
"name": "FrameworksServicesTests_android_server_power"
},
{
- "name": "PowerServiceTests",
- "options": [
- {"include-filter": "com.android.server.power"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "PowerServiceTests_server_power"
},
{
- "name": "CtsStatsdAtomHostTestCases",
- "options": [
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"},
- {"include-filter": "android.cts.statsdatom.powermanager"}
- ],
+ "name": "CtsStatsdAtomHostTestCases_statsdatom_powermanager",
"file_patterns": [
"(/|^)ThermalManagerService.java"
]
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 680b1ac..cb8e1a0 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -5031,9 +5031,7 @@
if (mPretendScreenOff != pretendScreenOff) {
mPretendScreenOff = pretendScreenOff;
final int primaryScreenState = mPerDisplayBatteryStats[0].screenState;
- noteScreenStateLocked(0, primaryScreenState,
- mClock.elapsedRealtime(), mClock.uptimeMillis(),
- mClock.currentTimeMillis());
+ noteScreenStateLocked(0, primaryScreenState);
}
}
@@ -5554,15 +5552,29 @@
}
}
+ private static String getScreenStateTag(
+ int display, int state, @Display.StateReason int reason) {
+ return String.format(
+ "display=%d state=%s reason=%s",
+ display, Display.stateToString(state), Display.stateReasonToString(reason));
+ }
+
@GuardedBy("this")
public void noteScreenStateLocked(int display, int state) {
- noteScreenStateLocked(display, state, mClock.elapsedRealtime(), mClock.uptimeMillis(),
- mClock.currentTimeMillis());
+ noteScreenStateLocked(display, state, Display.STATE_REASON_UNKNOWN,
+ mClock.elapsedRealtime(), mClock.uptimeMillis(), mClock.currentTimeMillis());
}
@GuardedBy("this")
public void noteScreenStateLocked(int display, int displayState,
- long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
+ @Display.StateReason int displayStateReason, long elapsedRealtimeMs, long uptimeMs,
+ long currentTimeMs) {
+ if (Flags.batteryStatsScreenStateEvent()) {
+ mHistory.recordEvent(
+ elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_DISPLAY_STATE_CHANGED,
+ getScreenStateTag(display, displayState, displayStateReason),
+ Process.INVALID_UID);
+ }
// Battery stats relies on there being 4 states. To accommodate this, new states beyond the
// original 4 are mapped to one of the originals.
if (displayState > MAX_TRACKED_SCREEN_STATE) {
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index cc0a283..05d29f5 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -68,3 +68,11 @@
description: "Disable deprecated BatteryUsageStatsAtom pulled atom"
bug: "324602949"
}
+
+flag {
+ name: "battery_stats_screen_state_event"
+ namespace: "backstage_power"
+ description: "Guards the battery stats event for screen state changes."
+ bug: "364350206"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
index 945a340..41e3d00 100644
--- a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
+++ b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java
@@ -17,6 +17,7 @@
package com.android.server.security;
import static android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE;
+import static android.security.attestationverification.AttestationVerificationManager.PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS;
import static android.security.attestationverification.AttestationVerificationManager.PARAM_PUBLIC_KEY;
import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE;
import static android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS;
@@ -174,8 +175,8 @@
MyDumpData dumpData = new MyDumpData();
- int result =
- verifyAttestationInternal(localBindingType, requirements, attestation, dumpData);
+ int result = verifyAttestationInternal(localBindingType, requirements, attestation,
+ dumpData);
dumpData.mResult = result;
mDumpLogger.logAttempt(dumpData);
return result;
@@ -222,7 +223,8 @@
final var attestationExtension = fromCertificate(leafCertificate);
// Second: verify if the attestation satisfies the "peer device" profile.
- if (!checkAttestationForPeerDeviceProfile(attestationExtension, dumpData)) {
+ if (!checkAttestationForPeerDeviceProfile(requirements, attestationExtension,
+ dumpData)) {
failed = true;
}
@@ -400,6 +402,7 @@
}
private boolean checkAttestationForPeerDeviceProfile(
+ @NonNull Bundle requirements,
@NonNull AndroidKeystoreAttestationVerificationAttributes attestationAttributes,
MyDumpData dumpData) {
boolean result = true;
@@ -461,30 +464,37 @@
result = false;
}
- // Patch level integer YYYYMM is expected to be within 1 year of today.
- if (!isValidPatchLevel(attestationAttributes.getKeyOsPatchLevel())) {
+ int maxPatchLevelDiffMonths = requirements.getInt(PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS,
+ MAX_PATCH_AGE_MONTHS);
+
+ // Patch level integer YYYYMM is expected to be within maxPatchLevelDiffMonths of today.
+ if (!isValidPatchLevel(attestationAttributes.getKeyOsPatchLevel(),
+ maxPatchLevelDiffMonths)) {
debugVerboseLog("OS patch level is not within valid range.");
result = false;
} else {
dumpData.mOsPatchLevelInRange = true;
}
- // Patch level integer YYYYMMDD is expected to be within 1 year of today.
- if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel())) {
+ // Patch level integer YYYYMMDD is expected to be within maxPatchLevelDiffMonths of today.
+ if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel(),
+ maxPatchLevelDiffMonths)) {
debugVerboseLog("Boot patch level is not within valid range.");
result = false;
} else {
dumpData.mKeyBootPatchLevelInRange = true;
}
- if (!isValidPatchLevel(attestationAttributes.getKeyVendorPatchLevel())) {
+ if (!isValidPatchLevel(attestationAttributes.getKeyVendorPatchLevel(),
+ maxPatchLevelDiffMonths)) {
debugVerboseLog("Vendor patch level is not within valid range.");
result = false;
} else {
dumpData.mKeyVendorPatchLevelInRange = true;
}
- if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel())) {
+ if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel(),
+ maxPatchLevelDiffMonths)) {
debugVerboseLog("Boot patch level is not within valid range.");
result = false;
} else {
@@ -525,7 +535,7 @@
* is not enough. Therefore, we also confirm the patch level for the remote and local device are
* similar.
*/
- private boolean isValidPatchLevel(int patchLevel) {
+ private boolean isValidPatchLevel(int patchLevel, int maxPatchLevelDiffMonths) {
LocalDate currentDate = mTestSystemDate != null
? mTestSystemDate : LocalDate.now(ZoneId.systemDefault());
@@ -543,7 +553,9 @@
return false;
}
- // Check local patch date is not in last year of system clock.
+ // Check local patch date is not in last year of system clock. If the local patch already
+ // has a year's worth of bugs and vulnerabilities, it has no security meanings to check the
+ // remote patch level.
if (ChronoUnit.MONTHS.between(localPatchDate, currentDate) > MAX_PATCH_AGE_MONTHS) {
return true;
}
@@ -559,19 +571,9 @@
int patchMonth = Integer.parseInt(remoteDeviceDateStr.substring(4, 6));
LocalDate remotePatchDate = LocalDate.of(patchYear, patchMonth, 1);
- // Check patch dates are within 1 year of each other
- boolean IsRemotePatchWithinOneYearOfLocalPatch;
- if (remotePatchDate.compareTo(localPatchDate) > 0) {
- IsRemotePatchWithinOneYearOfLocalPatch = ChronoUnit.MONTHS.between(
- localPatchDate, remotePatchDate) <= MAX_PATCH_AGE_MONTHS;
- } else if (remotePatchDate.compareTo(localPatchDate) < 0) {
- IsRemotePatchWithinOneYearOfLocalPatch = ChronoUnit.MONTHS.between(
- remotePatchDate, localPatchDate) <= MAX_PATCH_AGE_MONTHS;
- } else {
- IsRemotePatchWithinOneYearOfLocalPatch = true;
- }
-
- return IsRemotePatchWithinOneYearOfLocalPatch;
+ // Check patch dates are within the max patch level diff of each other
+ return Math.abs(ChronoUnit.MONTHS.between(localPatchDate, remotePatchDate))
+ <= maxPatchLevelDiffMonths;
}
/**
diff --git a/services/core/java/com/android/server/security/TEST_MAPPING b/services/core/java/com/android/server/security/TEST_MAPPING
index 29d52ff..284e08e 100644
--- a/services/core/java/com/android/server/security/TEST_MAPPING
+++ b/services/core/java/com/android/server/security/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsSecurityTestCases",
- "options": [
- {
- "include-filter": "android.security.cts.FileIntegrityManagerTest"
- }
- ],
+ "name": "CtsSecurityTestCases_cts_fileintegritymanagertest",
"file_patterns": ["FileIntegrity[^/]*\\.java"]
}
]
diff --git a/services/core/java/com/android/server/statusbar/TEST_MAPPING b/services/core/java/com/android/server/statusbar/TEST_MAPPING
index 67ea557..8c7e74c 100644
--- a/services/core/java/com/android/server/statusbar/TEST_MAPPING
+++ b/services/core/java/com/android/server/statusbar/TEST_MAPPING
@@ -1,29 +1,10 @@
{
"presubmit": [
{
- "name": "CtsTileServiceTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTileServiceTestCases"
},
{
- "name": "CtsAppTestCases",
- "options": [
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.app.cts.RequestTileServiceAddTest"
- }
- ]
+ "name": "CtsAppTestCases_cts_requesttileserviceaddtest"
}
]
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/timedetector/TEST_MAPPING b/services/core/java/com/android/server/timedetector/TEST_MAPPING
index 17d327e..f57b819 100644
--- a/services/core/java/com/android/server/timedetector/TEST_MAPPING
+++ b/services/core/java/com/android/server/timedetector/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
"name": "FrameworksTimeServicesTests"
diff --git a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
index 004d7996..a237c34 100644
--- a/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
+++ b/services/core/java/com/android/server/timezonedetector/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTimeTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTimeTestCases"
},
{
"name": "FrameworksTimeServicesTests"
diff --git a/services/core/java/com/android/server/trust/TEST_MAPPING b/services/core/java/com/android/server/trust/TEST_MAPPING
index 0de7c28..4c08455 100644
--- a/services/core/java/com/android/server/trust/TEST_MAPPING
+++ b/services/core/java/com/android/server/trust/TEST_MAPPING
@@ -1,41 +1,17 @@
{
"presubmit": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
],
"postsubmit": [
{
- "name": "FrameworksMockingServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.trust"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksMockingServicesTests_android_server_trust"
}
],
"trust-tablet": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
]
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 953aae9..457196b 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -89,6 +89,7 @@
import com.android.internal.widget.LockSettingsStateListener;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.servicewatcher.CurrentUserServiceSupplier;
import com.android.server.servicewatcher.ServiceWatcher;
import com.android.server.utils.Slogf;
@@ -170,6 +171,7 @@
private final ActivityManager mActivityManager;
private FingerprintManager mFingerprintManager;
private FaceManager mFaceManager;
+ private UserManagerInternal mUserManagerInternal;
private enum TrustState {
// UNTRUSTED means that TrustManagerService is currently *not* giving permission for the
@@ -1064,6 +1066,8 @@
Log.w(TAG, "Unable to check keyguard lock state", e);
}
currentUserIsUnlocked = unlockedUser == id;
+ } else if (isVisibleBackgroundUser(id)) {
+ showingKeyguard = !mUserManager.isUserUnlocked(id);
}
final boolean deviceLocked = secure && showingKeyguard && !trusted
&& !biometricAuthenticated;
@@ -1095,6 +1099,16 @@
}
}
+ private boolean isVisibleBackgroundUser(int userId) {
+ if (!mUserManager.isVisibleBackgroundUsersSupported()) {
+ return false;
+ }
+ if (mUserManagerInternal == null) {
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ }
+ return mUserManagerInternal.isVisibleBackgroundFullUser(userId);
+ }
+
private void notifyTrustAgentsOfDeviceLockState(int userId, boolean isLocked) {
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo agent = mActiveAgents.valueAt(i);
diff --git a/services/core/java/com/android/server/uri/TEST_MAPPING b/services/core/java/com/android/server/uri/TEST_MAPPING
index 0d756bb..45e3051 100644
--- a/services/core/java/com/android/server/uri/TEST_MAPPING
+++ b/services/core/java/com/android/server/uri/TEST_MAPPING
@@ -4,24 +4,7 @@
"name": "FrameworksServicesTests_android_server_uri"
},
{
- "name": "CtsStorageHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testGrantUriPermission"
- },
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testGrantUriPermission29"
- },
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone"
- },
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone28"
- },
- {
- "include-filter": "android.appsecurity.cts.ExternalStorageHostTest#testMediaNone29"
- }
- ]
+ "name": "CtsStorageHostTestCases_android_server_uri"
}
],
"postsubmit": [
@@ -34,12 +17,7 @@
]
},
{
- "name": "CtsWindowManagerDeviceWindow",
- "options": [
- {
- "include-filter": "android.server.wm.window.CrossAppDragAndDropTests"
- }
- ]
+ "name": "CtsWindowManagerDeviceWindow_window_crossappdraganddroptests"
}
]
}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
index 195e91c..49825f1 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
@@ -64,13 +64,36 @@
String targetPkg, int targetUserId);
/**
- * Same as {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int)}, but with an
- * extra parameter {@code requireContentUriPermissionFromCaller}, which is the value from {@link
- * android.R.attr#requireContentUriPermissionFromCaller} attribute.
+ * Same as {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int)}, but with:
+ * - {@code requireContentUriPermissionFromCaller}, which is the value from {@link
+ * android.R.attr#requireContentUriPermissionFromCaller} attribute.
+ * - {@code requestHashCode}, which is required to differentiate activity launches for logging
+ * ContentOrFileUriEventReported message.
*/
NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
String targetPkg, int targetUserId,
- @RequiredContentUriPermission int requireContentUriPermissionFromCaller);
+ @RequiredContentUriPermission int requireContentUriPermissionFromCaller,
+ int requestHashCode);
+
+ /**
+ * Notify that an activity launch request has been completed and perform the following actions:
+ * - If the activity launch was unsuccessful, then clean up all the collected the content URIs
+ * that were passed during that launch.
+ * - If the activity launch was successful, then log cog content URIs that were passed during
+ * that launch. Specifically:
+ * - The caller didn't have read permission to them.
+ * - The activity's {@link android.R.attr#requireContentUriPermissionFromCaller} was set to
+ * "none".
+ *
+ * <p>Note that:
+ * - The API has to be called after
+ * {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int, int, int)} was called.
+ * - The API is not idempotent, i.e. content URIs may be logged only once because the API clears
+ * the content URIs after logging.
+ */
+ void notifyActivityLaunchRequestCompleted(int requestHashCode, boolean isSuccessfulLaunch,
+ String intentAction, int callingUid, String callingActivityName, int calleeUid,
+ String calleeActivityName, boolean isStartActivityForResult);
/**
* Extend a previously calculated set of permissions grants to the given
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index a581b08..3479b6c 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -24,6 +24,7 @@
import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_NONE;
+import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_READ;
import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_READ_OR_WRITE;
import static android.content.pm.ActivityInfo.isRequiredContentUriPermissionRead;
import static android.content.pm.ActivityInfo.isRequiredContentUriPermissionWrite;
@@ -39,6 +40,8 @@
import static android.os.Process.myUid;
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.FrameworkStatsLog.CONTENT_OR_FILE_URI_EVENT_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.CONTENT_OR_FILE_URI_EVENT_REPORTED__EVENT_TYPE__CONTENT_URI_WITHOUT_CALLER_READ_PERMISSION;
import static com.android.server.uri.UriGrantsManagerService.H.PERSIST_URI_GRANTS_MSG;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -78,6 +81,7 @@
import android.provider.Downloads;
import android.text.format.DateUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -86,6 +90,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -153,6 +158,22 @@
private final SparseArray<ArrayMap<GrantUri, UriPermission>>
mGrantedUriPermissions = new SparseArray<>();
+ /**
+ * Global map of activity launches to sets of passed content URIs. Specifically:
+ * - The caller didn't have read permission to them.
+ * - The callee activity's {@link android.R.attr#requireContentUriPermissionFromCaller} was set
+ * to "none".
+ *
+ * <p>This map is used for logging the ContentOrFileUriEventReported message.
+ *
+ * <p>The launch id is the ActivityStarter.Request#hashCode and has to be received from
+ * ActivityStarter to {@link #checkGrantUriPermissionFromIntentUnlocked(int, String, Intent,
+ * int, NeededUriGrants, int, Integer, Integer)}.
+ */
+ @GuardedBy("mLaunchToContentUrisWithoutCallerReadPermission")
+ private final SparseArray<ArraySet<Uri>> mLaunchToContentUrisWithoutCallerReadPermission =
+ new SparseArray<>();
+
private UriGrantsManagerService() {
this(SystemServiceManager.ensureSystemDir(), "uri-grants");
}
@@ -613,7 +634,8 @@
/** Like checkGrantUriPermission, but takes an Intent. */
private NeededUriGrants checkGrantUriPermissionFromIntentUnlocked(int callingUid,
String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId,
- @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller) {
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ Integer requestHashCode) {
if (DEBUG) Slog.v(TAG,
"Checking URI perm to data=" + (intent != null ? intent.getData() : null)
+ " clip=" + (intent != null ? intent.getClipData() : null)
@@ -635,8 +657,9 @@
}
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCallerOnIntentExtraStream(intent, contentUserHint,
- mode, callingUid, requireContentUriPermissionFromCaller);
+ enforceRequireContentUriPermissionFromCallerOnIntentExtraStreamUnlocked(intent,
+ contentUserHint, mode, callingUid, requireContentUriPermissionFromCaller,
+ requestHashCode);
}
Uri data = intent.getData();
@@ -660,8 +683,9 @@
if (data != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, data, mode);
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCaller(requireContentUriPermissionFromCaller,
- grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, mode,
targetUid);
@@ -678,8 +702,9 @@
if (uri != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg,
grantUri, mode, targetUid);
@@ -694,7 +719,7 @@
if (clipIntent != null) {
NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentUnlocked(
callingUid, targetPkg, clipIntent, mode, needed, targetUserId,
- requireContentUriPermissionFromCaller);
+ requireContentUriPermissionFromCaller, requestHashCode);
if (newNeeded != null) {
needed = newNeeded;
}
@@ -706,17 +731,32 @@
return needed;
}
- private void enforceRequireContentUriPermissionFromCaller(
+ private void enforceRequireContentUriPermissionFromCallerUnlocked(
@RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
- GrantUri grantUri, int uid) {
- // Ignore if requireContentUriPermissionFromCaller hasn't been set or the URI is a
+ GrantUri grantUri, int callingUid, Integer requestHashCode) {
+ // Exit early if requireContentUriPermissionFromCaller hasn't been set or the URI is a
// non-content URI.
if (requireContentUriPermissionFromCaller == null
|| requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_NONE
|| !ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
+ tryAddingContentUriWithoutCallerReadPermissionWhenAttributeIsNoneUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid, requestHashCode);
return;
}
+ final boolean hasPermission = hasRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid);
+
+ if (!hasPermission) {
+ throw new SecurityException("You can't launch this activity because you don't have the"
+ + " required " + ActivityInfo.requiredContentUriPermissionToShortString(
+ requireContentUriPermissionFromCaller) + " access to " + grantUri.uri);
+ }
+ }
+
+ private boolean hasRequireContentUriPermissionFromCallerUnlocked(
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ GrantUri grantUri, int uid) {
final boolean readMet = !isRequiredContentUriPermissionRead(
requireContentUriPermissionFromCaller)
|| checkContentUriPermissionFullUnlocked(grantUri, uid,
@@ -727,26 +767,48 @@
|| checkContentUriPermissionFullUnlocked(grantUri, uid,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- boolean hasPermission =
- requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_READ_OR_WRITE
- ? (readMet || writeMet) : (readMet && writeMet);
+ return requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_READ_OR_WRITE
+ ? (readMet || writeMet) : (readMet && writeMet);
+ }
- if (!hasPermission) {
- throw new SecurityException("You can't launch this activity because you don't have the"
- + " required " + ActivityInfo.requiredContentUriPermissionToShortString(
- requireContentUriPermissionFromCaller) + " access to " + grantUri.uri);
+ private void tryAddingContentUriWithoutCallerReadPermissionWhenAttributeIsNoneUnlocked(
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ GrantUri grantUri, int callingUid, Integer requestHashCode) {
+ // We're interested in requireContentUriPermissionFromCaller that is set to
+ // CONTENT_URI_PERMISSION_NONE and content URIs. Hence, ignore if
+ // requireContentUriPermissionFromCaller is not set to CONTENT_URI_PERMISSION_NONE or the
+ // URI is a non-content URI.
+ if (requireContentUriPermissionFromCaller == null
+ || requireContentUriPermissionFromCaller != CONTENT_URI_PERMISSION_NONE
+ || !ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())
+ || requestHashCode == null) {
+ return;
+ }
+
+ if (!hasRequireContentUriPermissionFromCallerUnlocked(CONTENT_URI_PERMISSION_READ, grantUri,
+ callingUid)) {
+ synchronized (mLaunchToContentUrisWithoutCallerReadPermission) {
+ if (mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode) == null) {
+ mLaunchToContentUrisWithoutCallerReadPermission
+ .put(requestHashCode, new ArraySet<>());
+ }
+ mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode)
+ .add(grantUri.uri);
+ }
}
}
- private void enforceRequireContentUriPermissionFromCallerOnIntentExtraStream(Intent intent,
- int contentUserHint, int mode, int callingUid,
- @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller) {
+ private void enforceRequireContentUriPermissionFromCallerOnIntentExtraStreamUnlocked(
+ Intent intent, int contentUserHint, int mode, int callingUid,
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ Integer requestHashCode) {
try {
final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri.class);
if (uri != null) {
final GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
} catch (BadParcelableException e) {
Slog.w(TAG, "Failed to unparcel an URI in EXTRA_STREAM, skipping"
@@ -759,8 +821,9 @@
if (uris != null) {
for (int i = uris.size() - 1; i >= 0; i--) {
final GrantUri grantUri = GrantUri.resolve(contentUserHint, uris.get(i), mode);
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
}
} catch (BadParcelableException e) {
@@ -769,6 +832,37 @@
}
}
+ private void notifyActivityLaunchRequestCompletedUnlocked(Integer requestHashCode,
+ boolean isSuccessfulLaunch, String intentAction, int callingUid,
+ String callingActivityName, int calleeUid, String calleeActivityName,
+ boolean isStartActivityForResult) {
+ ArraySet<Uri> contentUris;
+ synchronized (mLaunchToContentUrisWithoutCallerReadPermission) {
+ contentUris = mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode);
+ mLaunchToContentUrisWithoutCallerReadPermission.remove(requestHashCode);
+ }
+ if (!isSuccessfulLaunch || contentUris == null) return;
+
+ final String[] authorities = new String[contentUris.size()];
+ final String[] schemes = new String[contentUris.size()];
+ for (int i = contentUris.size() - 1; i >= 0; i--) {
+ Uri uri = contentUris.valueAt(i);
+ authorities[i] = uri.getAuthority();
+ schemes[i] = uri.getScheme();
+ }
+ FrameworkStatsLog.write(CONTENT_OR_FILE_URI_EVENT_REPORTED,
+ CONTENT_OR_FILE_URI_EVENT_REPORTED__EVENT_TYPE__CONTENT_URI_WITHOUT_CALLER_READ_PERMISSION,
+ intentAction,
+ callingUid,
+ callingActivityName,
+ calleeUid,
+ calleeActivityName,
+ isStartActivityForResult,
+ String.join(",", authorities),
+ String.join(",", schemes),
+ /* uri_mime_type */ null);
+ }
+
@GuardedBy("mLock")
private void readGrantedUriPermissionsLocked() {
if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()");
@@ -1645,23 +1739,36 @@
public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
String targetPkg, int targetUserId) {
return internalCheckGrantUriPermissionFromIntent(intent, callingUid, targetPkg,
- targetUserId, /* requireContentUriPermissionFromCaller */ null);
+ targetUserId, /* requireContentUriPermissionFromCaller */ null,
+ /* requestHashCode */ null);
}
@Override
public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
- String targetPkg, int targetUserId, int requireContentUriPermissionFromCaller) {
+ String targetPkg, int targetUserId, int requireContentUriPermissionFromCaller,
+ int requestHashCode) {
return internalCheckGrantUriPermissionFromIntent(intent, callingUid, targetPkg,
- targetUserId, requireContentUriPermissionFromCaller);
+ targetUserId, requireContentUriPermissionFromCaller, requestHashCode);
+ }
+
+ @Override
+ public void notifyActivityLaunchRequestCompleted(int requestHashCode,
+ boolean isSuccessfulLaunch, String intentAction, int callingUid,
+ String callingActivityName, int calleeUid, String calleeActivityName,
+ boolean isStartActivityForResult) {
+ UriGrantsManagerService.this.notifyActivityLaunchRequestCompletedUnlocked(
+ requestHashCode, isSuccessfulLaunch, intentAction, callingUid,
+ callingActivityName, calleeUid, calleeActivityName,
+ isStartActivityForResult);
}
private NeededUriGrants internalCheckGrantUriPermissionFromIntent(Intent intent,
int callingUid, String targetPkg, int targetUserId,
- @Nullable Integer requireContentUriPermissionFromCaller) {
+ @Nullable Integer requireContentUriPermissionFromCaller, Integer requestHashCode) {
final int mode = (intent != null) ? intent.getFlags() : 0;
return UriGrantsManagerService.this.checkGrantUriPermissionFromIntentUnlocked(
callingUid, targetPkg, intent, mode, null, targetUserId,
- requireContentUriPermissionFromCaller);
+ requireContentUriPermissionFromCaller, requestHashCode);
}
@Override
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 8d378a0..b574782 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -177,6 +177,10 @@
/** Default number of parallel SAs requested */
static final int TUNNEL_AGGREGATION_SA_COUNT_MAX_DEFAULT = 1;
+ // The returned string of
+ // TelephonyManager#getNetworkTypeName(TelephonyManager.NETWORK_TYPE_UNKNOWN)
+ private static final String NETWORK_TYPE_STRING_UNKNOWN = "UNKNOWN";
+
// Matches DataConnection.NETWORK_TYPE private constant, and magic string from
// ConnectivityManager#getNetworkTypeName()
@VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -1815,9 +1819,7 @@
.setLegacyType(ConnectivityManager.TYPE_MOBILE)
.setLegacyTypeName(NETWORK_INFO_NETWORK_TYPE_STRING)
.setLegacySubType(TelephonyManager.NETWORK_TYPE_UNKNOWN)
- .setLegacySubTypeName(
- TelephonyManager.getNetworkTypeName(
- TelephonyManager.NETWORK_TYPE_UNKNOWN))
+ .setLegacySubTypeName(NETWORK_TYPE_STRING_UNKNOWN)
.setLegacyExtraInfo(NETWORK_INFO_EXTRA_INFO)
.build();
diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
index 3f8d39e..2b0ca08 100644
--- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
+++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java
@@ -360,7 +360,10 @@
final NetworkRequest.Builder nrBuilder =
getBaseNetworkRequestBuilder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
+ .setNetworkSpecifier(
+ new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(subId)
+ .build());
for (CapabilityMatchCriteria capMatchCriteria : capsMatchCriteria) {
final int cap = capMatchCriteria.capability;
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
index cae6b34..006a5bb 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
@@ -16,6 +16,8 @@
package com.android.server.vibrator;
+import static android.os.vibrator.Flags.hapticFeedbackInputSourceCustomizationEnabled;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
@@ -121,7 +123,6 @@
return getVibrationForHapticFeedback(effectId);
}
- // TODO(b/354049335): handle input source customized VibrationAttributes.
/**
* Provides the {@link VibrationAttributes} that should be used for a haptic feedback.
*
@@ -131,7 +132,7 @@
* @param privFlags Additional private flags as per {@link HapticFeedbackConstants}.
* @return the {@link VibrationAttributes} that should be used for the provided haptic feedback.
*/
- public VibrationAttributes getVibrationAttributesForHapticFeedback(int effectId,
+ public VibrationAttributes getVibrationAttributes(int effectId,
@HapticFeedbackConstants.Flags int flags,
@HapticFeedbackConstants.PrivateFlags int privFlags) {
VibrationAttributes attrs;
@@ -142,10 +143,13 @@
break;
case HapticFeedbackConstants.ASSISTANT_BUTTON:
case HapticFeedbackConstants.LONG_PRESS_POWER_BUTTON:
+ attrs = HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES;
+ break;
case HapticFeedbackConstants.SCROLL_TICK:
case HapticFeedbackConstants.SCROLL_ITEM_FOCUS:
case HapticFeedbackConstants.SCROLL_LIMIT:
- attrs = HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES;
+ attrs = hapticFeedbackInputSourceCustomizationEnabled() ? TOUCH_VIBRATION_ATTRIBUTES
+ : HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES;
break;
case HapticFeedbackConstants.KEYBOARD_TAP:
case HapticFeedbackConstants.KEYBOARD_RELEASE:
@@ -158,19 +162,32 @@
default:
attrs = TOUCH_VIBRATION_ATTRIBUTES;
}
+ return getVibrationAttributesWithFlags(attrs, effectId, flags);
+ }
- int vibFlags = 0;
- boolean bypassVibrationIntensitySetting =
- (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0;
- if (bypassVibrationIntensitySetting) {
- vibFlags |= VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
+ /**
+ * Similar to {@link #getVibrationAttributes(int, int, int)} but also handles
+ * input source customization.
+ *
+ * @param inputSource the {@link InputDevice.Source} that customizes the
+ * {@link VibrationAttributes}.
+ */
+ public VibrationAttributes getVibrationAttributes(int effectId,
+ int inputSource,
+ @HapticFeedbackConstants.Flags int flags,
+ @HapticFeedbackConstants.PrivateFlags int privFlags) {
+ if (hapticFeedbackInputSourceCustomizationEnabled()
+ && inputSource == InputDevice.SOURCE_ROTARY_ENCODER) {
+ switch (effectId) {
+ case HapticFeedbackConstants.SCROLL_TICK,
+ HapticFeedbackConstants.SCROLL_ITEM_FOCUS,
+ HapticFeedbackConstants.SCROLL_LIMIT -> {
+ return getVibrationAttributesWithFlags(HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES,
+ effectId, flags);
+ }
+ }
}
- if (shouldBypassInterruptionPolicy(effectId)) {
- vibFlags |= VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
- }
-
- return vibFlags == 0 ? attrs : new VibrationAttributes.Builder(attrs)
- .setFlags(vibFlags).build();
+ return getVibrationAttributes(effectId, flags, privFlags);
}
/**
@@ -344,6 +361,20 @@
return IME_FEEDBACK_VIBRATION_ATTRIBUTES;
}
+ private VibrationAttributes getVibrationAttributesWithFlags(VibrationAttributes attrs,
+ int effectId, int flags) {
+ int vibFlags = 0;
+ if ((flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0) {
+ vibFlags |= VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
+ }
+ if (shouldBypassInterruptionPolicy(effectId)) {
+ vibFlags |= VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
+ }
+
+ return vibFlags == 0 ? attrs : new VibrationAttributes.Builder(attrs)
+ .setFlags(vibFlags).build();
+ }
+
private static boolean shouldBypassInterruptionPolicy(int effectId) {
switch (effectId) {
case HapticFeedbackConstants.SCROLL_TICK:
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index ab4a4d8..4c1e16c 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -128,15 +128,20 @@
* before the release callback.
*/
boolean runVibrationOnVibrationThread(VibrationStepConductor conductor) {
- synchronized (mLock) {
- if (mRequestedActiveConductor != null) {
- Slog.wtf(TAG, "Attempt to start vibration when one already running");
- return false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrationOnVibrationThread");
+ try {
+ synchronized (mLock) {
+ if (mRequestedActiveConductor != null) {
+ Slog.wtf(TAG, "Attempt to start vibration when one already running");
+ return false;
+ }
+ mRequestedActiveConductor = conductor;
+ mLock.notifyAll();
}
- mRequestedActiveConductor = conductor;
- mLock.notifyAll();
+ return true;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- return true;
}
@Override
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 4fc0b74..3c47850 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -23,6 +23,7 @@
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.VibrationEffect;
import android.os.VibratorInfo;
import android.os.vibrator.PrebakedSegment;
@@ -123,21 +124,26 @@
/** Reruns the query to the vibrator to load the {@link VibratorInfo}, if not yet successful. */
public void reloadVibratorInfoIfNeeded() {
- // Early check outside lock, for quick return.
- if (mVibratorInfoLoadSuccessful) {
- return;
- }
- synchronized (mLock) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#reloadVibratorInfoIfNeeded");
+ try {
+ // Early check outside lock, for quick return.
if (mVibratorInfoLoadSuccessful) {
return;
}
- int vibratorId = mVibratorInfo.getId();
- VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
- mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder);
- mVibratorInfo = vibratorInfoBuilder.build();
- if (!mVibratorInfoLoadSuccessful) {
- Slog.e(TAG, "Failed retry of HAL getInfo for vibrator " + vibratorId);
+ synchronized (mLock) {
+ if (mVibratorInfoLoadSuccessful) {
+ return;
+ }
+ int vibratorId = mVibratorInfo.getId();
+ VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
+ mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder);
+ mVibratorInfo = vibratorInfoBuilder.build();
+ if (!mVibratorInfoLoadSuccessful) {
+ Slog.e(TAG, "Failed retry of HAL getInfo for vibrator " + vibratorId);
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -193,8 +199,13 @@
/** Return {@code true} if the underlying vibrator is currently available, false otherwise. */
public boolean isAvailable() {
- synchronized (mLock) {
- return mNativeWrapper.isAvailable();
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#isAvailable");
+ try {
+ synchronized (mLock) {
+ return mNativeWrapper.isAvailable();
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -204,12 +215,17 @@
* <p>This will affect the state of {@link #isUnderExternalControl()}.
*/
public void setExternalControl(boolean externalControl) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
- return;
- }
- synchronized (mLock) {
- mIsUnderExternalControl = externalControl;
- mNativeWrapper.setExternalControl(externalControl);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "setExternalControl(" + externalControl + ")");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+ return;
+ }
+ synchronized (mLock) {
+ mIsUnderExternalControl = externalControl;
+ mNativeWrapper.setExternalControl(externalControl);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -218,28 +234,38 @@
* if given {@code effect} is {@code null}.
*/
public void updateAlwaysOn(int id, @Nullable PrebakedSegment prebaked) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
- return;
- }
- synchronized (mLock) {
- if (prebaked == null) {
- mNativeWrapper.alwaysOnDisable(id);
- } else {
- mNativeWrapper.alwaysOnEnable(id, prebaked.getEffectId(),
- prebaked.getEffectStrength());
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#updateAlwaysOn");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ return;
}
+ synchronized (mLock) {
+ if (prebaked == null) {
+ mNativeWrapper.alwaysOnDisable(id);
+ } else {
+ mNativeWrapper.alwaysOnEnable(id, prebaked.getEffectId(),
+ prebaked.getEffectStrength());
+ }
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
/** Set the vibration amplitude. This will NOT affect the state of {@link #isVibrating()}. */
public void setAmplitude(float amplitude) {
- synchronized (mLock) {
- if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
- mNativeWrapper.setAmplitude(amplitude);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#setAmplitude");
+ try {
+ synchronized (mLock) {
+ if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+ mNativeWrapper.setAmplitude(amplitude);
+ }
+ if (mIsVibrating) {
+ mCurrentAmplitude = amplitude;
+ }
}
- if (mIsVibrating) {
- mCurrentAmplitude = amplitude;
- }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -253,13 +279,18 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(long milliseconds, long vibrationId) {
- synchronized (mLock) {
- long duration = mNativeWrapper.on(milliseconds, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on");
+ try {
+ synchronized (mLock) {
+ long duration = mNativeWrapper.on(milliseconds, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
}
- return duration;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -273,6 +304,7 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(VibrationEffect.VendorEffect vendorEffect, long vibrationId) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (vendor)");
synchronized (mLock) {
Parcel vendorData = Parcel.obtain();
try {
@@ -288,6 +320,7 @@
return duration;
} finally {
vendorData.recycle();
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
}
@@ -302,14 +335,19 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(PrebakedSegment prebaked, long vibrationId) {
- synchronized (mLock) {
- long duration = mNativeWrapper.perform(prebaked.getEffectId(),
- prebaked.getEffectStrength(), vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (Prebaked)");
+ try {
+ synchronized (mLock) {
+ long duration = mNativeWrapper.perform(prebaked.getEffectId(),
+ prebaked.getEffectStrength(), vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
}
- return duration;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -323,16 +361,21 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(PrimitiveSegment[] primitives, long vibrationId) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
- return 0;
- }
- synchronized (mLock) {
- long duration = mNativeWrapper.compose(primitives, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (Primitive)");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+ return 0;
}
- return duration;
+ synchronized (mLock) {
+ long duration = mNativeWrapper.compose(primitives, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -345,17 +388,22 @@
* @return The duration of the effect playing, or 0 if unsupported.
*/
public long on(RampSegment[] primitives, long vibrationId) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
- return 0;
- }
- synchronized (mLock) {
- int braking = mVibratorInfo.getDefaultBraking();
- long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (PWLE)");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
+ return 0;
}
- return duration;
+ synchronized (mLock) {
+ int braking = mVibratorInfo.getDefaultBraking();
+ long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -365,10 +413,15 @@
* <p>This will affect the state of {@link #isVibrating()}.
*/
public void off() {
- synchronized (mLock) {
- mNativeWrapper.off();
- mCurrentAmplitude = 0;
- notifyListenerOnVibrating(false);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#off");
+ try {
+ synchronized (mLock) {
+ mNativeWrapper.off();
+ mCurrentAmplitude = 0;
+ notifyListenerOnVibrating(false);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 799934a..a76d8d6 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -462,20 +462,31 @@
@Override // Binder call
public void performHapticFeedback(int uid, int deviceId, String opPkg, int constant,
String reason, int flags, int privFlags) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedback");
// Note that the `performHapticFeedback` method does not take a token argument from the
// caller, and instead, uses this service as the token. This is to mitigate performance
// impact that would otherwise be caused due to marshal latency. Haptic feedback effects are
// short-lived, so we don't need to cancel when the process dies.
- performHapticFeedbackInternal(uid, deviceId, opPkg, constant, reason, /* token= */
- this, flags, privFlags);
+ try {
+ performHapticFeedbackInternal(uid, deviceId, opPkg, constant, reason, /* token= */
+ this, flags, privFlags);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override // Binder call
public void performHapticFeedbackForInputDevice(int uid, int deviceId, String opPkg,
int constant, int inputDeviceId, int inputSource, String reason, int flags,
int privFlags) {
- performHapticFeedbackForInputDeviceInternal(uid, deviceId, opPkg, constant, inputDeviceId,
- inputSource, reason, /* token= */ this, flags, privFlags);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedbackForInputDevice");
+ try {
+ performHapticFeedbackForInputDeviceInternal(uid, deviceId, opPkg, constant,
+ inputDeviceId,
+ inputSource, reason, /* token= */ this, flags, privFlags);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
/**
@@ -498,7 +509,7 @@
}
return performHapticFeedbackWithEffect(uid, deviceId, opPkg, constant, reason, token,
hapticVibrationProvider.getVibration(constant),
- hapticVibrationProvider.getVibrationAttributesForHapticFeedback(
+ hapticVibrationProvider.getVibrationAttributes(
constant, flags, privFlags));
}
@@ -523,8 +534,8 @@
}
return performHapticFeedbackWithEffect(uid, deviceId, opPkg, constant, reason, token,
hapticVibrationProvider.getVibration(constant, inputSource),
- hapticVibrationProvider.getVibrationAttributesForHapticFeedback(
- constant, flags, privFlags));
+ hapticVibrationProvider.getVibrationAttributes(constant, inputSource, flags,
+ privFlags));
}
private HalVibration performHapticFeedbackWithEffect(int uid, int deviceId, String opPkg,
@@ -919,30 +930,25 @@
@GuardedBy("mLock")
@Nullable
private Vibration.EndInfo startVibrationOnThreadLocked(VibrationStepConductor conductor) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationThreadLocked");
- try {
- HalVibration vib = conductor.getVibration();
- int mode = startAppOpModeLocked(vib.callerInfo);
- switch (mode) {
- case AppOpsManager.MODE_ALLOWED:
- Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- // Make sure mCurrentVibration is set while triggering the VibrationThread.
- mCurrentVibration = conductor;
- if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) {
- // Shouldn't happen. The method call already logs a wtf.
- mCurrentVibration = null; // Aborted.
- return new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING);
- }
- return null;
- case AppOpsManager.MODE_ERRORED:
- Slog.w(TAG, "Start AppOpsManager operation errored for uid "
- + vib.callerInfo.uid);
- return new Vibration.EndInfo(Status.IGNORED_ERROR_APP_OPS);
- default:
- return new Vibration.EndInfo(Status.IGNORED_APP_OPS);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ HalVibration vib = conductor.getVibration();
+ int mode = startAppOpModeLocked(vib.callerInfo);
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
+ // Make sure mCurrentVibration is set while triggering the VibrationThread.
+ mCurrentVibration = conductor;
+ if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) {
+ // Shouldn't happen. The method call already logs a wtf.
+ mCurrentVibration = null; // Aborted.
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING);
+ }
+ return null;
+ case AppOpsManager.MODE_ERRORED:
+ Slog.w(TAG, "Start AppOpsManager operation errored for uid "
+ + vib.callerInfo.uid);
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_APP_OPS);
+ default:
+ return new Vibration.EndInfo(Status.IGNORED_APP_OPS);
}
}
@@ -1050,21 +1056,16 @@
@GuardedBy("mLock")
private void reportFinishedVibrationLocked(Vibration.EndInfo vibrationEndInfo) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- try {
- HalVibration vib = mCurrentVibration.getVibration();
- if (DEBUG) {
- Slog.d(TAG, "Reporting vibration " + vib.id + " finished with "
- + vibrationEndInfo);
- }
- // DO NOT write metrics at this point, wait for the VibrationThread to report the
- // vibration was released, after all cleanup. The metrics will be reported then.
- endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false);
- finishAppOpModeLocked(vib.callerInfo);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ HalVibration vib = mCurrentVibration.getVibration();
+ if (DEBUG) {
+ Slog.d(TAG, "Reporting vibration " + vib.id + " finished with "
+ + vibrationEndInfo);
}
+ // DO NOT write metrics at this point, wait for the VibrationThread to report the
+ // vibration was released, after all cleanup. The metrics will be reported then.
+ endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false);
+ finishAppOpModeLocked(vib.callerInfo);
}
private void onSyncedVibrationComplete(long vibrationId) {
@@ -1418,40 +1419,34 @@
@GuardedBy("mLock")
@Nullable
- private SparseArray<PrebakedSegment> fixupAlwaysOnEffectsLocked(
- CombinedVibration effect) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "fixupAlwaysOnEffectsLocked");
- try {
- SparseArray<VibrationEffect> effects;
- if (effect instanceof CombinedVibration.Mono) {
- VibrationEffect syncedEffect = ((CombinedVibration.Mono) effect).getEffect();
- effects = transformAllVibratorsLocked(unused -> syncedEffect);
- } else if (effect instanceof CombinedVibration.Stereo) {
- effects = ((CombinedVibration.Stereo) effect).getEffects();
- } else {
- // Only synced combinations can be used for always-on effects.
- return null;
- }
- SparseArray<PrebakedSegment> result = new SparseArray<>();
- for (int i = 0; i < effects.size(); i++) {
- PrebakedSegment prebaked = extractPrebakedSegment(effects.valueAt(i));
- if (prebaked == null) {
- Slog.e(TAG, "Only prebaked effects supported for always-on.");
- return null;
- }
- int vibratorId = effects.keyAt(i);
- VibratorController vibrator = mVibrators.get(vibratorId);
- if (vibrator != null && vibrator.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
- result.put(vibratorId, prebaked);
- }
- }
- if (result.size() == 0) {
- return null;
- }
- return result;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ private SparseArray<PrebakedSegment> fixupAlwaysOnEffectsLocked(CombinedVibration effect) {
+ SparseArray<VibrationEffect> effects;
+ if (effect instanceof CombinedVibration.Mono) {
+ VibrationEffect syncedEffect = ((CombinedVibration.Mono) effect).getEffect();
+ effects = transformAllVibratorsLocked(unused -> syncedEffect);
+ } else if (effect instanceof CombinedVibration.Stereo) {
+ effects = ((CombinedVibration.Stereo) effect).getEffects();
+ } else {
+ // Only synced combinations can be used for always-on effects.
+ return null;
}
+ SparseArray<PrebakedSegment> result = new SparseArray<>();
+ for (int i = 0; i < effects.size(); i++) {
+ PrebakedSegment prebaked = extractPrebakedSegment(effects.valueAt(i));
+ if (prebaked == null) {
+ Slog.e(TAG, "Only prebaked effects supported for always-on.");
+ return null;
+ }
+ int vibratorId = effects.keyAt(i);
+ VibratorController vibrator = mVibrators.get(vibratorId);
+ if (vibrator != null && vibrator.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ result.put(vibratorId, prebaked);
+ }
+ }
+ if (result.size() == 0) {
+ return null;
+ }
+ return result;
}
@Nullable
@@ -1580,25 +1575,42 @@
@Override
public boolean prepareSyncedVibration(long requiredCapabilities, int[] vibratorIds) {
- if ((mCapabilities & requiredCapabilities) != requiredCapabilities) {
- // This sync step requires capabilities this device doesn't have, skipping sync...
- return false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "prepareSyncedVibration");
+ try {
+ if ((mCapabilities & requiredCapabilities) != requiredCapabilities) {
+ // This sync step requires capabilities this device doesn't have, skipping
+ // sync...
+ return false;
+ }
+ return mNativeWrapper.prepareSynced(vibratorIds);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- return mNativeWrapper.prepareSynced(vibratorIds);
}
@Override
public boolean triggerSyncedVibration(long vibrationId) {
- return mNativeWrapper.triggerSynced(vibrationId);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "triggerSyncedVibration");
+ try {
+ return mNativeWrapper.triggerSynced(vibrationId);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override
public void cancelSyncedVibration() {
- mNativeWrapper.cancelSynced();
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "cancelSyncedVibration");
+ try {
+ mNativeWrapper.cancelSynced();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override
public void noteVibratorOn(int uid, long duration) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "noteVibratorOn");
try {
if (duration <= 0) {
// Tried to turn vibrator ON and got:
@@ -1616,16 +1628,21 @@
mFrameworkStatsLogger.writeVibratorStateOnAsync(uid, duration);
} catch (RemoteException e) {
Slog.e(TAG, "Error logging VibratorStateChanged to ON", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@Override
public void noteVibratorOff(int uid) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "noteVibratorOff");
try {
mBatteryStatsService.noteVibratorOff(uid);
mFrameworkStatsLogger.writeVibratorStateOffAsync(uid);
} catch (RemoteException e) {
Slog.e(TAG, "Error logging VibratorStateChanged to OFF", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -1634,11 +1651,16 @@
if (DEBUG) {
Slog.d(TAG, "Vibration " + vibrationId + " finished with " + vibrationEndInfo);
}
- synchronized (mLock) {
- if (mCurrentVibration != null
- && mCurrentVibration.getVibration().id == vibrationId) {
- reportFinishedVibrationLocked(vibrationEndInfo);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onVibrationCompleted");
+ try {
+ synchronized (mLock) {
+ if (mCurrentVibration != null
+ && mCurrentVibration.getVibration().id == vibrationId) {
+ reportFinishedVibrationLocked(vibrationEndInfo);
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -1647,34 +1669,40 @@
if (DEBUG) {
Slog.d(TAG, "VibrationThread released after finished vibration");
}
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Processing VibrationThread released callback");
- }
- if (Build.IS_DEBUGGABLE && mCurrentVibration != null
- && mCurrentVibration.getVibration().id != vibrationId) {
- Slog.wtf(TAG, TextUtils.formatSimple(
- "VibrationId mismatch on release. expected=%d, released=%d",
- mCurrentVibration.getVibration().id, vibrationId));
- }
- if (mCurrentVibration != null) {
- // This is when we consider the current vibration complete, so report metrics.
- mFrameworkStatsLogger.writeVibrationReportedAsync(
- mCurrentVibration.getVibration().getStatsInfo(
- /* completionUptimeMillis= */ SystemClock.uptimeMillis()));
- mCurrentVibration = null;
- }
- if (mNextVibration != null) {
- VibrationStepConductor nextConductor = mNextVibration;
- mNextVibration = null;
- Vibration.EndInfo vibrationEndInfo = startVibrationOnThreadLocked(
- nextConductor);
- if (vibrationEndInfo != null) {
- // Failed to start the vibration, end it and report metrics right away.
- endVibrationLocked(nextConductor.getVibration(),
- vibrationEndInfo, /* shouldWriteStats= */ true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onVibrationThreadReleased: " + vibrationId);
+ try {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(TAG, "Processing VibrationThread released callback");
+ }
+ if (Build.IS_DEBUGGABLE && mCurrentVibration != null
+ && mCurrentVibration.getVibration().id != vibrationId) {
+ Slog.wtf(TAG, TextUtils.formatSimple(
+ "VibrationId mismatch on release. expected=%d, released=%d",
+ mCurrentVibration.getVibration().id, vibrationId));
+ }
+ if (mCurrentVibration != null) {
+ // This is when we consider the current vibration complete, so report
+ // metrics.
+ mFrameworkStatsLogger.writeVibrationReportedAsync(
+ mCurrentVibration.getVibration().getStatsInfo(
+ /* completionUptimeMillis= */ SystemClock.uptimeMillis()));
+ mCurrentVibration = null;
+ }
+ if (mNextVibration != null) {
+ VibrationStepConductor nextConductor = mNextVibration;
+ mNextVibration = null;
+ Vibration.EndInfo vibrationEndInfo = startVibrationOnThreadLocked(
+ nextConductor);
+ if (vibrationEndInfo != null) {
+ // Failed to start the vibration, end it and report metrics right away.
+ endVibrationLocked(nextConductor.getVibration(),
+ vibrationEndInfo, /* shouldWriteStats= */ true);
+ }
}
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
}
@@ -1917,22 +1945,17 @@
@GuardedBy("mLock")
private void endExternalVibrateLocked(Vibration.EndInfo vibrationEndInfo,
boolean continueExternalControl) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "endExternalVibrateLocked");
- try {
- if (mCurrentExternalVibration == null) {
- return;
- }
- mCurrentExternalVibration.unlinkToDeath();
- if (!continueExternalControl) {
- setExternalControl(false, mCurrentExternalVibration.stats);
- }
- // The external control was turned off, end it and report metrics right away.
- endVibrationLocked(mCurrentExternalVibration, vibrationEndInfo,
- /* shouldWriteStats= */ true);
- mCurrentExternalVibration = null;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ if (mCurrentExternalVibration == null) {
+ return;
}
+ mCurrentExternalVibration.unlinkToDeath();
+ if (!continueExternalControl) {
+ setExternalControl(false, mCurrentExternalVibration.stats);
+ }
+ // The external control was turned off, end it and report metrics right away.
+ endVibrationLocked(mCurrentExternalVibration, vibrationEndInfo,
+ /* shouldWriteStats= */ true);
+ mCurrentExternalVibration = null;
}
private HapticFeedbackVibrationProvider getHapticVibrationProvider() {
@@ -1987,143 +2010,160 @@
@Override
public ExternalVibrationScale onExternalVibrationStart(ExternalVibration vib) {
- // Create Vibration.Stats as close to the received request as possible, for tracking.
- ExternalVibrationSession externalVibration = new ExternalVibrationSession(vib);
- // Mute the request until we run all the checks and accept the vibration.
- externalVibration.muteScale();
- boolean alreadyUnderExternalControl = false;
- boolean waitForCompletion = false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onExternalVibrationStart");
+ try {
+ // Create Vibration.Stats as close to the received request as possible, for
+ // tracking.
+ ExternalVibrationSession externalVibration = new ExternalVibrationSession(vib);
+ // Mute the request until we run all the checks and accept the vibration.
+ externalVibration.muteScale();
+ boolean alreadyUnderExternalControl = false;
+ boolean waitForCompletion = false;
- synchronized (mLock) {
- if (!hasExternalControlCapability()) {
- endVibrationLocked(externalVibration,
- new Vibration.EndInfo(Status.IGNORED_UNSUPPORTED),
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ synchronized (mLock) {
+ if (!hasExternalControlCapability()) {
+ endVibrationLocked(externalVibration,
+ new Vibration.EndInfo(Status.IGNORED_UNSUPPORTED),
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
- vib.getUid(), -1 /*owningUid*/, true /*exported*/)
- != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
- + " tried to play externally controlled vibration"
- + " without VIBRATE permission, ignoring.");
- endVibrationLocked(externalVibration,
- new Vibration.EndInfo(Status.IGNORED_MISSING_PERMISSION),
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ if (ActivityManager.checkComponentPermission(
+ android.Manifest.permission.VIBRATE,
+ vib.getUid(), -1 /*owningUid*/, true /*exported*/)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
+ + " tried to play externally controlled vibration"
+ + " without VIBRATE permission, ignoring.");
+ endVibrationLocked(externalVibration,
+ new Vibration.EndInfo(Status.IGNORED_MISSING_PERMISSION),
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(
- externalVibration.callerInfo);
+ Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(
+ externalVibration.callerInfo);
- if (vibrationEndInfo == null
- && mCurrentExternalVibration != null
- && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
- // We are already playing this external vibration, so we can return the same
- // scale calculated in the previous call to this method.
- return mCurrentExternalVibration.getScale();
- }
+ if (vibrationEndInfo == null
+ && mCurrentExternalVibration != null
+ && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
+ // We are already playing this external vibration, so we can return the same
+ // scale calculated in the previous call to this method.
+ return mCurrentExternalVibration.getScale();
+ }
- if (vibrationEndInfo == null) {
- // Check if ongoing vibration is more important than this vibration.
- vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(externalVibration);
- }
+ if (vibrationEndInfo == null) {
+ // Check if ongoing vibration is more important than this vibration.
+ vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(externalVibration);
+ }
- if (vibrationEndInfo != null) {
- endVibrationLocked(externalVibration, vibrationEndInfo,
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ if (vibrationEndInfo != null) {
+ endVibrationLocked(externalVibration, vibrationEndInfo,
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- if (mCurrentExternalVibration == null) {
- // If we're not under external control right now, then cancel any normal
- // vibration that may be playing and ready the vibrator for external control.
- if (mCurrentVibration != null) {
+ if (mCurrentExternalVibration == null) {
+ // If we're not under external control right now, then cancel any normal
+ // vibration that may be playing and ready the vibrator for external
+ // control.
+ if (mCurrentVibration != null) {
+ externalVibration.stats.reportInterruptedAnotherVibration(
+ mCurrentVibration.getVibration().callerInfo);
+ clearNextVibrationLocked(
+ new Vibration.EndInfo(Status.IGNORED_FOR_EXTERNAL,
+ externalVibration.callerInfo));
+ mCurrentVibration.notifyCancelled(
+ new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
+ externalVibration.callerInfo),
+ /* immediate= */ true);
+ waitForCompletion = true;
+ }
+ } else {
+ // At this point we have an externally controlled vibration playing already.
+ // Since the interface defines that only one externally controlled
+ // vibration can
+ // play at a time, we need to first mute the ongoing vibration and then
+ // return
+ // a scale from this function for the new one, so we can be assured that the
+ // ongoing will be muted in favor of the new vibration.
+ //
+ // Note that this doesn't support multiple concurrent external controls,
+ // as we would need to mute the old one still if it came from a different
+ // controller.
+ alreadyUnderExternalControl = true;
+ mCurrentExternalVibration.notifyEnded();
externalVibration.stats.reportInterruptedAnotherVibration(
- mCurrentVibration.getVibration().callerInfo);
- clearNextVibrationLocked(
- new Vibration.EndInfo(Status.IGNORED_FOR_EXTERNAL,
- externalVibration.callerInfo));
- mCurrentVibration.notifyCancelled(
+ mCurrentExternalVibration.callerInfo);
+ endExternalVibrateLocked(
new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
externalVibration.callerInfo),
- /* immediate= */ true);
- waitForCompletion = true;
+ /* continueExternalControl= */ true);
}
- } else {
- // At this point we have an externally controlled vibration playing already.
- // Since the interface defines that only one externally controlled vibration can
- // play at a time, we need to first mute the ongoing vibration and then return
- // a scale from this function for the new one, so we can be assured that the
- // ongoing will be muted in favor of the new vibration.
- //
- // Note that this doesn't support multiple concurrent external controls, as we
- // would need to mute the old one still if it came from a different controller.
- alreadyUnderExternalControl = true;
- mCurrentExternalVibration.notifyEnded();
- externalVibration.stats.reportInterruptedAnotherVibration(
- mCurrentExternalVibration.callerInfo);
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
- externalVibration.callerInfo),
- /* continueExternalControl= */ true);
- }
- VibrationAttributes attrs = fixupVibrationAttributes(vib.getVibrationAttributes(),
- /* effect= */ null);
- if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
- // Force update of user settings before checking if this vibration effect should
- // be ignored or scaled.
- mVibrationSettings.update();
- }
-
- mCurrentExternalVibration = externalVibration;
- externalVibration.linkToDeath(this::onExternalVibrationBinderDied);
- externalVibration.scale(mVibrationScaler, attrs.getUsage());
- }
-
- if (waitForCompletion) {
- if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
- Slog.e(TAG, "Timed out waiting for vibration to cancel");
- synchronized (mLock) {
- // Trigger endExternalVibrateLocked to unlink to death recipient.
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.IGNORED_ERROR_CANCELLING),
- /* continueExternalControl= */ false);
- // Mute the request, vibration will be ignored.
- externalVibration.muteScale();
+ VibrationAttributes attrs = fixupVibrationAttributes(
+ vib.getVibrationAttributes(),
+ /* effect= */ null);
+ if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
+ // Force update of user settings before checking if this vibration effect
+ // should be ignored or scaled.
+ mVibrationSettings.update();
}
- return externalVibration.getScale();
+
+ mCurrentExternalVibration = externalVibration;
+ externalVibration.linkToDeath(this::onExternalVibrationBinderDied);
+ externalVibration.scale(mVibrationScaler, attrs.getUsage());
}
- }
- if (!alreadyUnderExternalControl) {
+
+ if (waitForCompletion) {
+ if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
+ Slog.e(TAG, "Timed out waiting for vibration to cancel");
+ synchronized (mLock) {
+ // Trigger endExternalVibrateLocked to unlink to death recipient.
+ endExternalVibrateLocked(
+ new Vibration.EndInfo(Status.IGNORED_ERROR_CANCELLING),
+ /* continueExternalControl= */ false);
+ // Mute the request, vibration will be ignored.
+ externalVibration.muteScale();
+ }
+ return externalVibration.getScale();
+ }
+ }
+ if (!alreadyUnderExternalControl) {
+ if (DEBUG) {
+ Slog.d(TAG, "Vibrator going under external control.");
+ }
+ setExternalControl(true, externalVibration.stats);
+ }
if (DEBUG) {
- Slog.d(TAG, "Vibrator going under external control.");
+ Slog.d(TAG, "Playing external vibration: " + vib);
}
- setExternalControl(true, externalVibration.stats);
+ // Vibrator will start receiving data from external channels after this point.
+ // Report current time as the vibration start time, for debugging.
+ externalVibration.stats.reportStarted();
+ return externalVibration.getScale();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- if (DEBUG) {
- Slog.d(TAG, "Playing external vibration: " + vib);
- }
- // Vibrator will start receiving data from external channels after this point.
- // Report current time as the vibration start time, for debugging.
- externalVibration.stats.reportStarted();
- return externalVibration.getScale();
}
@Override
public void onExternalVibrationStop(ExternalVibration vib) {
- synchronized (mLock) {
- if (mCurrentExternalVibration != null
- && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
- if (DEBUG) {
- Slog.d(TAG, "Stopping external vibration: " + vib);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onExternalVibrationStop");
+ try {
+ synchronized (mLock) {
+ if (mCurrentExternalVibration != null
+ && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Stopping external vibration: " + vib);
+ }
+ endExternalVibrateLocked(
+ new Vibration.EndInfo(Status.FINISHED),
+ /* continueExternalControl= */ false);
}
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.FINISHED),
- /* continueExternalControl= */ false);
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperData.java b/services/core/java/com/android/server/wallpaper/WallpaperData.java
index b792f79..a698429 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperData.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperData.java
@@ -80,8 +80,11 @@
*/
ComponentName wallpaperComponent;
+ // TODO(b/347235611) Remove this field
/**
* The component name of the wallpaper that should be set next.
+ *
+ * @deprecated
*/
ComponentName nextWallpaperComponent;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
index 4aefb54..b15facb 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperDataParser.java
@@ -16,6 +16,7 @@
package com.android.server.wallpaper;
+import static android.app.Flags.removeNextWallpaperComponent;
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
import static android.app.WallpaperManager.ORIENTATION_UNKNOWN;
@@ -187,13 +188,24 @@
}
String comp = parser.getAttributeValue(null, "component");
- wallpaperToParse.nextWallpaperComponent = comp != null
- ? ComponentName.unflattenFromString(comp)
- : null;
- if (wallpaperToParse.nextWallpaperComponent == null
- || "android".equals(wallpaperToParse.nextWallpaperComponent
- .getPackageName())) {
- wallpaperToParse.nextWallpaperComponent = mImageWallpaper;
+ if (removeNextWallpaperComponent()) {
+ wallpaperToParse.wallpaperComponent = comp != null
+ ? ComponentName.unflattenFromString(comp)
+ : null;
+ if (wallpaperToParse.wallpaperComponent == null
+ || "android".equals(wallpaperToParse.wallpaperComponent
+ .getPackageName())) {
+ wallpaperToParse.wallpaperComponent = mImageWallpaper;
+ }
+ } else {
+ wallpaperToParse.nextWallpaperComponent = comp != null
+ ? ComponentName.unflattenFromString(comp)
+ : null;
+ if (wallpaperToParse.nextWallpaperComponent == null
+ || "android".equals(wallpaperToParse.nextWallpaperComponent
+ .getPackageName())) {
+ wallpaperToParse.nextWallpaperComponent = mImageWallpaper;
+ }
}
if (multiCrop()) {
@@ -206,8 +218,12 @@
Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
Slog.v(TAG, "mName:" + wallpaper.name);
- Slog.v(TAG, "mNextWallpaperComponent:"
- + wallpaper.nextWallpaperComponent);
+ if (removeNextWallpaperComponent()) {
+ Slog.v(TAG, "mWallpaperComponent:" + wallpaper.wallpaperComponent);
+ } else {
+ Slog.v(TAG, "mNextWallpaperComponent:"
+ + wallpaper.nextWallpaperComponent);
+ }
}
}
}
@@ -324,7 +340,9 @@
getAttributeInt(parser, "totalCropTop", 0),
getAttributeInt(parser, "totalCropRight", 0),
getAttributeInt(parser, "totalCropBottom", 0));
- if (multiCrop() && mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
+ ComponentName componentName = removeNextWallpaperComponent() ? wallpaper.wallpaperComponent
+ : wallpaper.nextWallpaperComponent;
+ if (multiCrop() && mImageWallpaper.equals(componentName)) {
wallpaper.mCropHints = new SparseArray<>();
for (Pair<Integer, String> pair: screenDimensionPairs()) {
Rect cropHint = new Rect(
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 78359bd..6cc37dd 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -20,6 +20,7 @@
import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_WALLPAPER_INTERNAL;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.app.Flags.removeNextWallpaperComponent;
import static android.app.WallpaperManager.COMMAND_REAPPLY;
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
@@ -1474,12 +1475,14 @@
}
}
}
- if (wallpaper.nextWallpaperComponent != null) {
- int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
- .getPackageName());
- if (change == PACKAGE_PERMANENT_CHANGE
- || change == PACKAGE_TEMPORARY_CHANGE) {
- wallpaper.nextWallpaperComponent = null;
+ if (!removeNextWallpaperComponent()) {
+ if (wallpaper.nextWallpaperComponent != null) {
+ int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
+ .getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ wallpaper.nextWallpaperComponent = null;
+ }
}
}
if (wallpaper.wallpaperComponent != null
@@ -1494,14 +1497,17 @@
clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, false, null);
}
}
- if (wallpaper.nextWallpaperComponent != null
- && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
- try {
- mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- } catch (NameNotFoundException e) {
- wallpaper.nextWallpaperComponent = null;
+ if (!removeNextWallpaperComponent()) {
+ if (wallpaper.nextWallpaperComponent != null
+ && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
+ try {
+ mContext.getPackageManager().getServiceInfo(
+ wallpaper.nextWallpaperComponent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+ } catch (NameNotFoundException e) {
+ wallpaper.nextWallpaperComponent = null;
+ }
}
}
return changed;
@@ -1628,7 +1634,14 @@
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
// If we think we're going to be using the system image wallpaper imagery, make
// sure we have something to render
- if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
+ boolean isImageComponent;
+ if (removeNextWallpaperComponent()) {
+ isImageComponent = wallpaper.wallpaperComponent == null
+ || mImageWallpaper.equals(wallpaper.wallpaperComponent);
+ } else {
+ isImageComponent = mImageWallpaper.equals(wallpaper.nextWallpaperComponent);
+ }
+ if (isImageComponent) {
// No crop file? Make sure we've finished the processing sequence if necessary
if (!wallpaper.cropExists()) {
if (DEBUG) {
@@ -1877,8 +1890,13 @@
if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = false;
if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = false;
- final ComponentName cname = wallpaper.wallpaperComponent != null ?
- wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+ final ComponentName cname;
+ if (removeNextWallpaperComponent()) {
+ cname = wallpaper.wallpaperComponent;
+ } else {
+ cname = (wallpaper.wallpaperComponent != null)
+ ? wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+ }
if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
// We failed to bind the desired wallpaper, but that might
// happen if the wallpaper isn't direct-boot aware
@@ -1905,10 +1923,12 @@
return;
}
Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
- // We might end up persisting the current wallpaper data
- // while locked, so pretend like the component was actually
- // bound into place
- wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
+ if (!removeNextWallpaperComponent()) {
+ // We might end up persisting the current wallpaper data
+ // while locked, so pretend like the component was actually
+ // bound into place
+ wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
+ }
final WallpaperData fallback = new WallpaperData(wallpaper.userId, wallpaper.mWhich);
// files from the previous static wallpaper may still be stored in memory.
@@ -3810,10 +3830,12 @@
wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
wallpaper.allowBackup = true; // by definition if it was restored
- if (wallpaper.nextWallpaperComponent != null
- && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
+ ComponentName componentName =
+ removeNextWallpaperComponent() ? wallpaper.wallpaperComponent
+ : wallpaper.nextWallpaperComponent;
+ if (componentName != null && !componentName.equals(mImageWallpaper)) {
wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_LIVE_SUCCESS;
- if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+ if (!bindWallpaperComponentLocked(componentName, false, false,
wallpaper, null)) {
// No such live wallpaper or other failure; fall back to the default
// live wallpaper (since the profile being restored indicated that the
@@ -3837,8 +3859,7 @@
if (success) {
mWallpaperCropper.generateCrop(wallpaper); // based on the new image + metadata
wallpaper.mBindSource = BindSource.RESTORE_SETTINGS_STATIC;
- bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
- wallpaper, null);
+ bindWallpaperComponentLocked(componentName, true, false, wallpaper, null);
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8c23eaa..ccc9b17 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2641,7 +2641,7 @@
return true;
}
// Only do transfer after transaction has done when starting window exist.
- if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommitCount > 0) {
+ if (mStartingData != null && mStartingData.mWaitForSyncTransactionCommit) {
mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_COPY_TO_CLIENT;
return true;
}
@@ -2804,11 +2804,9 @@
@Override
void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) {
- // Only add once per transition.
- final boolean added = wcAwaitingCommit.contains(this);
super.waitForSyncTransactionCommit(wcAwaitingCommit);
- if (!added && mStartingData != null) {
- mStartingData.mWaitForSyncTransactionCommitCount++;
+ if (mStartingData != null) {
+ mStartingData.mWaitForSyncTransactionCommit = true;
}
}
@@ -2819,7 +2817,7 @@
return;
}
final StartingData lastData = mStartingData;
- lastData.mWaitForSyncTransactionCommitCount--;
+ lastData.mWaitForSyncTransactionCommit = false;
if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_REMOVE_DIRECTLY) {
removeStartingWindowAnimation(lastData.mPrepareRemoveAnimation);
} else if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_COPY_TO_CLIENT) {
@@ -2849,7 +2847,7 @@
final boolean animate;
final boolean hasImeSurface;
if (mStartingData != null) {
- if (mStartingData.mWaitForSyncTransactionCommitCount > 0
+ if (mStartingData.mWaitForSyncTransactionCommit
|| mSyncState != SYNC_STATE_NONE) {
mStartingData.mRemoveAfterTransaction = AFTER_TRANSACTION_REMOVE_DIRECTLY;
mStartingData.mPrepareRemoveAnimation = prepareAnimation;
@@ -8152,13 +8150,17 @@
* into account orientation per-app overrides applied by the device manufacturers.
*/
@Override
+ @ActivityInfo.ScreenOrientation
protected int getOverrideOrientation() {
- if (mWmService.mConstants.mIgnoreActivityOrientationRequest
- && info.applicationInfo.category != ApplicationInfo.CATEGORY_GAME) {
- return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ final int candidateOrientation;
+ if (!mWmService.mConstants.mIgnoreActivityOrientationRequest
+ || info.applicationInfo.category == ApplicationInfo.CATEGORY_GAME) {
+ candidateOrientation = super.getOverrideOrientation();
+ } else {
+ candidateOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
return mAppCompatController.getOrientationPolicy()
- .overrideOrientationIfNeeded(super.getOverrideOrientation());
+ .overrideOrientationIfNeeded(candidateOrientation);
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 1822a80..bc11bac 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -603,7 +603,8 @@
.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid,
activityInfo.applicationInfo.packageName,
UserHandle.getUserId(activityInfo.applicationInfo.uid),
- activityInfo.requireContentUriPermissionFromCaller);
+ activityInfo.requireContentUriPermissionFromCaller,
+ /* requestHashCode */ this.hashCode());
} else {
intentGrants = supervisor.mService.mUgmInternal
.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid,
@@ -717,6 +718,9 @@
* @return The starter result.
*/
int execute() {
+ // Required for logging ContentOrFileUriEventReported in the finally block.
+ String callerActivityName = null;
+ ActivityRecord launchingRecord = null;
try {
onExecutionStarted();
@@ -737,6 +741,7 @@
? Binder.getCallingUid() : mRequest.realCallingUid;
launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
mRequest.intent, caller, callingUid);
+ callerActivityName = caller != null ? caller.info.name : null;
}
if (mRequest.intent != null) {
@@ -812,7 +817,7 @@
final ActivityOptions originalOptions = mRequest.activityOptions != null
? mRequest.activityOptions.getOriginalOptions() : null;
// Only track the launch time of activity that will be resumed.
- final ActivityRecord launchingRecord = mDoResume ? mLastStartActivityRecord : null;
+ launchingRecord = mDoResume ? mLastStartActivityRecord : null;
// If the new record is the one that started, a new activity has created.
final boolean newActivityCreated = mStartActivity == launchingRecord;
// Notify ActivityMetricsLogger that the activity has launched.
@@ -828,6 +833,23 @@
return getExternalResult(res);
}
} finally {
+ // Notify UriGrantsManagerService that activity launch completed. Required for logging
+ // the ContentOrFileUriEventReported message.
+ mSupervisor.mService.mUgmInternal.notifyActivityLaunchRequestCompleted(
+ mRequest.hashCode(),
+ // isSuccessfulLaunch
+ launchingRecord != null,
+ // Intent action
+ mRequest.intent != null ? mRequest.intent.getAction() : null,
+ mRequest.realCallingUid,
+ callerActivityName,
+ // Callee UID
+ mRequest.activityInfo != null
+ ? mRequest.activityInfo.applicationInfo.uid : INVALID_UID,
+ // Callee Activity name
+ mRequest.activityInfo != null ? mRequest.activityInfo.name : null,
+ // isStartActivityForResult
+ launchingRecord != null && launchingRecord.resultTo != null);
onExecutionComplete();
}
}
diff --git a/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java b/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
index 852ce04..9c861fe 100644
--- a/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
+++ b/services/core/java/com/android/server/wm/AppCompatConfigurationPersister.java
@@ -16,16 +16,13 @@
package com.android.server.wm;
-import static android.os.StrictMode.setThreadPolicy;
-
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Environment;
-import android.os.StrictMode;
-import android.os.StrictMode.ThreadPolicy;
import android.util.AtomicFile;
import android.util.Slog;
@@ -122,7 +119,7 @@
final File prefFiles = new File(configFolder, letterboxConfigurationFileName);
mConfigurationFile = new AtomicFile(prefFiles);
mPersisterQueue = persisterQueue;
- runWithDiskReadsThreadPolicy(this::readCurrentConfiguration);
+ readCurrentConfiguration();
}
/**
@@ -212,6 +209,7 @@
mDefaultTabletopModeReachabilitySupplier.get();
}
+ @MainThread
private void readCurrentConfiguration() {
if (!mConfigurationFile.exists()) {
useDefaultValue();
@@ -272,20 +270,6 @@
}
}
- // The LetterboxConfigurationDeviceConfig needs to access the
- // file with the current reachability position once when the
- // device boots. Because DisplayThread uses allowIo=false
- // accessing a file triggers a DiskReadViolation.
- // Here we use StrictMode to allow the current thread to read
- // the AtomicFile once in the current thread restoring the
- // original ThreadPolicy after that.
- private void runWithDiskReadsThreadPolicy(Runnable runnable) {
- final ThreadPolicy currentPolicy = StrictMode.getThreadPolicy();
- setThreadPolicy(new ThreadPolicy.Builder().permitDiskReads().build());
- runnable.run();
- setThreadPolicy(currentPolicy);
- }
-
private static class UpdateValuesCommand implements
PersisterQueue.WriteQueueItem<UpdateValuesCommand> {
diff --git a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
index 3be266e..f069dcd 100644
--- a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
@@ -145,11 +145,13 @@
}
}
- void updateSizeCompatScale(@NonNull Rect resolvedAppBounds, @NonNull Rect containerAppBounds) {
+ void updateSizeCompatScale(@NonNull Rect resolvedAppBounds, @NonNull Rect containerAppBounds,
+ @NonNull Configuration newParentConfig) {
mSizeCompatScale = mActivityRecord.mAppCompatController.getTransparentPolicy()
.findOpaqueNotFinishingActivityBelow()
.map(activityRecord -> mSizeCompatScale)
- .orElseGet(() -> calculateSizeCompatScale(resolvedAppBounds, containerAppBounds));
+ .orElseGet(() -> calculateSizeCompatScale(
+ resolvedAppBounds, containerAppBounds, newParentConfig));
}
void clearSizeCompatModeAttributes() {
@@ -290,7 +292,7 @@
// Calculates the scale the size compatibility bounds into the region which is available
// to application.
final float lastSizeCompatScale = mSizeCompatScale;
- updateSizeCompatScale(resolvedAppBounds, containerAppBounds);
+ updateSizeCompatScale(resolvedAppBounds, containerAppBounds, newParentConfiguration);
final int containerTopInset = containerAppBounds.top - containerBounds.top;
final boolean topNotAligned =
@@ -423,7 +425,7 @@
}
private float calculateSizeCompatScale(@NonNull Rect resolvedAppBounds,
- @NonNull Rect containerAppBounds) {
+ @NonNull Rect containerAppBounds, @NonNull Configuration newParentConfig) {
final int contentW = resolvedAppBounds.width();
final int contentH = resolvedAppBounds.height();
final int viewportW = containerAppBounds.width();
@@ -432,7 +434,8 @@
// original container or if it's a freeform window in desktop mode.
boolean shouldAllowUpscaling = !(contentW <= viewportW && contentH <= viewportH)
|| (canEnterDesktopMode(mActivityRecord.mAtmService.mContext)
- && mActivityRecord.getWindowingMode() == WINDOWING_MODE_FREEFORM);
+ && newParentConfig.windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_FREEFORM);
return shouldAllowUpscaling ? Math.min(
(float) viewportW / contentW, (float) viewportH / contentH) : 1f;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 10e0641..21212e5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -707,6 +707,8 @@
@Retention(RetentionPolicy.SOURCE)
@interface InputMethodTarget {}
+ /** The surface parent window of the IME container. */
+ private WindowContainer mInputMethodSurfaceParentWindow;
/** The surface parent of the IME container. */
@VisibleForTesting
SurfaceControl mInputMethodSurfaceParent;
@@ -1529,6 +1531,10 @@
return mDisplayRotation.getLastOrientation();
}
+ WindowContainer getImeParentWindow() {
+ return mInputMethodSurfaceParentWindow;
+ }
+
void registerRemoteAnimations(RemoteAnimationDefinition definition) {
mAppTransitionController.registerRemoteAnimations(definition);
}
@@ -4733,13 +4739,17 @@
Slog.i(TAG_WM, "ImeContainer is organized. Skip updateImeParent.");
}
// Leave the ImeContainer where the DisplayAreaPolicy placed it.
- // FEATURE_IME is organized by vendor so they are responible for placing the surface.
+ // FEATURE_IME is organized by vendor so they are responsible for placing the surface.
+ mInputMethodSurfaceParentWindow = null;
mInputMethodSurfaceParent = null;
return;
}
- final SurfaceControl newParent = computeImeParent();
+ final var newParentWindow = computeImeParent();
+ final SurfaceControl newParent =
+ newParentWindow != null ? newParentWindow.getSurfaceControl() : null;
if (newParent != null && newParent != mInputMethodSurfaceParent) {
+ mInputMethodSurfaceParentWindow = newParentWindow;
mInputMethodSurfaceParent = newParent;
getSyncTransaction().reparent(mImeWindowsContainer.mSurfaceControl, newParent);
if (DEBUG_IME_VISIBILITY) {
@@ -4800,7 +4810,7 @@
* Computes the window the IME should be attached to.
*/
@VisibleForTesting
- SurfaceControl computeImeParent() {
+ WindowContainer computeImeParent() {
if (!ImeTargetVisibilityPolicy.canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) {
return null;
}
@@ -4808,11 +4818,10 @@
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
if (shouldImeAttachedToApp()) {
- return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
+ return mImeLayeringTarget.mActivityRecord;
}
// Otherwise, we just attach it to where the display area policy put it.
- return mImeWindowsContainer.getParent() != null
- ? mImeWindowsContainer.getParent().getSurfaceControl() : null;
+ return mImeWindowsContainer.getParent();
}
void setLayoutNeeded() {
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 169a76f..5514294e 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -33,6 +33,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.InputApplicationHandle;
import android.view.InputChannel;
+import android.view.WindowInsets;
import android.window.InputTransferToken;
import com.android.internal.protolog.ProtoLog;
@@ -222,6 +223,10 @@
private boolean mIsFocusable;
+ // The EmbeddedWindow can only request the IME. All other insets types are requested by
+ // the host window.
+ private @WindowInsets.Type.InsetsType int mRequestedVisibleTypes = 0;
+
/**
* @param session calling session to check ownership of the window
* @param clientToken client token used to clean up the map if the embedding process dies
@@ -311,6 +316,27 @@
}
@Override
+ public boolean isRequestedVisible(@WindowInsets.Type.InsetsType int types) {
+ return (mRequestedVisibleTypes & types) != 0;
+ }
+
+ @Override
+ public @WindowInsets.Type.InsetsType int getRequestedVisibleTypes() {
+ return mRequestedVisibleTypes;
+ }
+
+ /**
+ * Only the IME can be requested from the EmbeddedWindow.
+ * @param requestedVisibleTypes other types than {@link WindowInsets.Type.IME} are
+ * not sent to system server via WindowlessWindowManager.
+ */
+ void setRequestedVisibleTypes(@WindowInsets.Type.InsetsType int requestedVisibleTypes) {
+ if (mRequestedVisibleTypes != requestedVisibleTypes) {
+ mRequestedVisibleTypes = requestedVisibleTypes;
+ }
+ }
+
+ @Override
public int getPid() {
return mOwnerPid;
}
@@ -375,6 +401,11 @@
@Override
public boolean shouldControlIme() {
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ // EmbeddedWindow should never be able to control the IME directly, but only the
+ // RemoteInsetsControlTarget.
+ return false;
+ }
return mHostWindowState != null;
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 43c3d05..e178203 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -268,7 +268,7 @@
// TODO(b/353463205) change statsToken to be NonNull, after the flag is permanently enabled
@Override
- protected boolean updateClientVisibility(InsetsControlTarget caller,
+ protected boolean updateClientVisibility(InsetsTarget caller,
@Nullable ImeTracker.Token statsToken) {
InsetsControlTarget controlTarget = getControlTarget();
if (caller != controlTarget) {
@@ -283,12 +283,13 @@
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_SET_REMOTE_TARGET_IME_VISIBILITY);
controlTarget.setImeInputTargetRequestedVisibility(imeVisible);
- } else {
+ } else if (caller instanceof InsetsControlTarget) {
// In case of a virtual display that cannot show the IME, the
// controlTarget will be null here, as no controlTarget was set yet. In
// that case, proceed similar to the multi window mode (fallback =
// RemoteInsetsControlTarget of the default display)
- controlTarget = mDisplayContent.getImeHostOrFallback(caller.getWindow());
+ controlTarget = mDisplayContent.getImeHostOrFallback(
+ ((InsetsControlTarget) caller).getWindow());
if (controlTarget != caller) {
ImeTracker.forLogging().onProgress(statsToken,
@@ -300,8 +301,7 @@
}
}
- WindowState windowState = caller.getWindow();
- invokeOnImeRequestedChangedListener(windowState, statsToken);
+ invokeOnImeRequestedChangedListener(caller, statsToken);
} else {
// TODO(b/353463205) add ImeTracker?
}
@@ -309,20 +309,16 @@
return false;
}
boolean changed = super.updateClientVisibility(caller, statsToken);
- if (!Flags.refactorInsetsController()) {
+ if (!Flags.refactorInsetsController() && caller instanceof InsetsControlTarget) {
if (changed && caller.isRequestedVisible(mSource.getType())) {
- reportImeDrawnForOrganizerIfNeeded(caller);
+ reportImeDrawnForOrganizerIfNeeded((InsetsControlTarget) caller);
}
}
changed |= mDisplayContent.onImeInsetsClientVisibilityUpdate();
if (Flags.refactorInsetsController()) {
if (changed) {
- // RemoteInsetsControlTarget does not have a window. In this case, we use the
- // windowState from the imeInputTarget
- WindowState windowState = caller.getWindow() != null ? caller.getWindow()
- : ((mDisplayContent.getImeInputTarget() != null)
- ? mDisplayContent.getImeInputTarget().getWindowState() : null);
- invokeOnImeRequestedChangedListener(windowState, statsToken);
+ invokeOnImeRequestedChangedListener(mDisplayContent.getImeInputTarget(),
+ statsToken);
} else {
// TODO(b/329229469) change phase and check cancelled / failed
ImeTracker.forLogging().onCancelled(statsToken,
@@ -334,32 +330,31 @@
void onInputTargetChanged(InputTarget target) {
if (Flags.refactorInsetsController() && target != null) {
- WindowState targetWin = target.getWindowState();
InsetsControlTarget imeControlTarget = getControlTarget();
- if (target != imeControlTarget && targetWin != null) {
+ if (target != imeControlTarget) {
// If the targetWin is not the imeControlTarget (=RemoteInsetsControlTarget) let it
// know about the new requestedVisibleTypes for the IME.
if (imeControlTarget != null) {
imeControlTarget.setImeInputTargetRequestedVisibility(
- (targetWin.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
+ (target.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
}
}
}
}
// TODO(b/353463205) check callers to see if we can make statsToken @NonNull
- private void invokeOnImeRequestedChangedListener(WindowState windowState,
+ private void invokeOnImeRequestedChangedListener(InsetsTarget insetsTarget,
@Nullable ImeTracker.Token statsToken) {
final var imeListener = mDisplayContent.mWmService.mOnImeRequestedChangedListener;
if (imeListener != null) {
- if (windowState != null) {
+ if (insetsTarget != null) {
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_POSTING_CHANGED_IME_VISIBILITY);
mDisplayContent.mWmService.mH.post(() -> {
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_INVOKING_IME_REQUESTED_LISTENER);
- imeListener.onImeRequestedChanged(windowState.mClient.asBinder(),
- windowState.isRequestedVisible(WindowInsets.Type.ime()), statsToken);
+ imeListener.onImeRequestedChanged(insetsTarget.getWindowToken(),
+ insetsTarget.isRequestedVisible(WindowInsets.Type.ime()), statsToken);
});
} else {
ImeTracker.forLogging().onFailed(statsToken,
@@ -676,7 +671,7 @@
return target == mDisplayContent.getImeFallback();
}
- private boolean isImeInputTarget(@NonNull InsetsControlTarget target) {
+ private boolean isImeInputTarget(@NonNull InsetsTarget target) {
return target == mDisplayContent.getImeInputTarget();
}
diff --git a/services/core/java/com/android/server/wm/InputTarget.java b/services/core/java/com/android/server/wm/InputTarget.java
index 0c0b794..40ce9db 100644
--- a/services/core/java/com/android/server/wm/InputTarget.java
+++ b/services/core/java/com/android/server/wm/InputTarget.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
/**
@@ -25,16 +24,13 @@
* Both WindowState and EmbeddedWindows can receive input. This consolidates some common properties
* of both targets.
*/
-interface InputTarget {
+interface InputTarget extends InsetsTarget {
/* Get the WindowState associated with the target. */
WindowState getWindowState();
/* Display id of the target. */
int getDisplayId();
- /* Client IWindow for the target. */
- IBinder getWindowToken();
-
/* Owning pid of the target. */
int getPid();
int getUid();
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 07e249a..7043aacf 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
+import android.os.IBinder;
import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.inputmethod.ImeTracker;
@@ -25,7 +26,7 @@
/**
* Generalization of an object that can control insets state.
*/
-interface InsetsControlTarget {
+interface InsetsControlTarget extends InsetsTarget {
/**
* Notifies the control target that the insets control has changed.
@@ -42,16 +43,17 @@
return null;
}
- /**
- * @return {@code true} if any of the {@link InsetsType} is requested visible by this target.
- */
+ @Override
+ default IBinder getWindowToken() {
+ return null;
+ }
+
+ @Override
default boolean isRequestedVisible(@InsetsType int types) {
return (WindowInsets.Type.defaultVisible() & types) != 0;
}
- /**
- * @return {@link InsetsType}s which are requested visible by this target.
- */
+ @Override
default @InsetsType int getRequestedVisibleTypes() {
return WindowInsets.Type.defaultVisible();
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 129078b..b414a862 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -434,7 +434,7 @@
return originalState;
}
- void onRequestedVisibleTypesChanged(InsetsControlTarget caller,
+ void onRequestedVisibleTypesChanged(InsetsTarget caller,
@Nullable ImeTracker.Token statsToken) {
mStateController.onRequestedVisibleTypesChanged(caller, statsToken);
checkAbortTransient(caller);
@@ -449,7 +449,7 @@
*
* @param caller who changed the insets state.
*/
- private void checkAbortTransient(InsetsControlTarget caller) {
+ private void checkAbortTransient(InsetsTarget caller) {
if (mShowingTransientTypes == 0) {
return;
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 8f90b2d..f0a4763 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -529,13 +529,27 @@
setClientVisible((WindowInsets.Type.defaultVisible() & mSource.getType()) != 0);
return;
}
+ boolean initiallyVisible = mClientVisible;
final Point surfacePosition = getWindowFrameSurfacePosition();
mAdapter = new ControlAdapter(surfacePosition);
if (mSource.getType() == WindowInsets.Type.ime()) {
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ if (mClientVisible && mServerVisible) {
+ WindowContainer imeParentWindow = mDisplayContent.getImeParentWindow();
+ // If the IME is attached to an app window, only consider it initially visible
+ // if the parent is visible and wasn't part of a transition.
+ initiallyVisible =
+ imeParentWindow != null && !imeParentWindow.inTransitionSelfOrParent()
+ && imeParentWindow.isVisible()
+ && imeParentWindow.isVisibleRequested();
+ } else {
+ initiallyVisible = false;
+ }
+ }
setClientVisible(target.isRequestedVisible(WindowInsets.Type.ime()));
}
final Transaction t = mWindowContainer.getSyncTransaction();
- mWindowContainer.startAnimation(t, mAdapter, !mClientVisible /* hidden */,
+ mWindowContainer.startAnimation(t, mAdapter, !initiallyVisible /* hidden */,
ANIMATION_TYPE_INSETS_CONTROL);
// The leash was just created. We cannot dispatch it until its surface transaction is
@@ -545,14 +559,16 @@
final SurfaceControl leash = mAdapter.mCapturedLeash;
mControlTarget = target;
updateVisibility();
- boolean initiallyVisible = mClientVisible;
if (mSource.getType() == WindowInsets.Type.ime()) {
- // The IME cannot be initially visible, see ControlAdapter#startAnimation below.
- // Also, the ImeInsetsSourceConsumer clears the client visibility upon losing control,
- // but this won't have reached here yet by the time the new control is created.
- // Note: The DisplayImeController needs the correct previous client's visibility, so we
- // only override the initiallyVisible here.
- initiallyVisible = false;
+ if (!android.view.inputmethod.Flags.refactorInsetsController()) {
+ // The IME cannot be initially visible, see ControlAdapter#startAnimation below.
+ // Also, the ImeInsetsSourceConsumer clears the client visibility upon losing
+ // control, but this won't have reached here yet by the time the new control is
+ // created.
+ // Note: The DisplayImeController needs the correct previous client's visibility,
+ // so we only override the initiallyVisible here.
+ initiallyVisible = false;
+ }
}
mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash,
initiallyVisible, surfacePosition, getInsetsHint());
@@ -598,7 +614,7 @@
mSeamlessRotating = false;
}
- boolean updateClientVisibility(InsetsControlTarget caller,
+ boolean updateClientVisibility(InsetsTarget caller,
@Nullable ImeTracker.Token statsToken) {
final boolean requestedVisible = caller.isRequestedVisible(mSource.getType());
if (caller != mControlTarget || requestedVisible == mClientVisible) {
@@ -799,7 +815,7 @@
@AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) {
// TODO(b/166736352): Check if we still need to control the IME visibility here.
if (mSource.getType() == WindowInsets.Type.ime()) {
- if (!android.view.inputmethod.Flags.refactorInsetsController() || !mClientVisible) {
+ if (!android.view.inputmethod.Flags.refactorInsetsController()) {
// TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed.
t.setAlpha(animationLeash, 1 /* alpha */);
t.hide(animationLeash);
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 481ecd3..3e39a45 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -219,7 +219,7 @@
}
}
- void onRequestedVisibleTypesChanged(InsetsControlTarget caller,
+ void onRequestedVisibleTypesChanged(InsetsTarget caller,
@Nullable ImeTracker.Token statsToken) {
boolean changed = false;
for (int i = mProviders.size() - 1; i >= 0; i--) {
@@ -238,7 +238,7 @@
}
}
- @InsetsType int getFakeControllingTypes(InsetsControlTarget target) {
+ @InsetsType int getFakeControllingTypes(InsetsTarget target) {
@InsetsType int types = 0;
for (int i = mProviders.size() - 1; i >= 0; i--) {
final InsetsSourceProvider provider = mProviders.valueAt(i);
diff --git a/services/core/java/com/android/server/wm/InsetsTarget.java b/services/core/java/com/android/server/wm/InsetsTarget.java
new file mode 100644
index 0000000..b918ca3
--- /dev/null
+++ b/services/core/java/com/android/server/wm/InsetsTarget.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 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.wm;
+
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.view.WindowInsets;
+
+/**
+ * A common parent for {@link InputTarget} and {@link InsetsControlTarget}: Some types (like the
+ * {@link EmbeddedWindowController.EmbeddedWindow}) should not be a control target for insets in
+ * general, but should be able to request the IME. To archive this, the InsetsTarget contains the
+ * minimal information that those interfaces share (and what is needed to show the IME.
+ */
+public interface InsetsTarget {
+
+ /**
+ * @return Client IWindow token for the target.
+ */
+ @Nullable
+ IBinder getWindowToken();
+
+ /**
+ * @param types The {@link WindowInsets.Type}s which requestedVisibility status is returned.
+ * @return {@code true} if any of the {@link WindowInsets.Type.InsetsType} is requested
+ * visible by this target.
+ */
+ boolean isRequestedVisible(@WindowInsets.Type.InsetsType int types);
+
+ /**
+ * @return {@link WindowInsets.Type.InsetsType}s which are requested visible by this target.
+ */
+ @WindowInsets.Type.InsetsType int getRequestedVisibleTypes();
+}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 2ea2aeb6..5550f3e 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -705,8 +705,25 @@
win.getDisplayContent().getInsetsPolicy().onRequestedVisibleTypesChanged(win,
imeStatsToken);
} else {
- ImeTracker.forLogging().onFailed(imeStatsToken,
- ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
+ EmbeddedWindowController.EmbeddedWindow embeddedWindow = null;
+ if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ embeddedWindow = mService.mEmbeddedWindowController.getByWindowToken(
+ window.asBinder());
+ }
+ if (embeddedWindow != null) {
+ // If there is no WindowState for the IWindow, it could be still an
+ // EmbeddedWindow. Therefore, check the EmbeddedWindowController as well
+ // TODO(b/329229469) Use different phase here
+ ImeTracker.forLogging().onProgress(imeStatsToken,
+ ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
+ embeddedWindow.setRequestedVisibleTypes(
+ requestedVisibleTypes & WindowInsets.Type.ime());
+ embeddedWindow.getDisplayContent().getInsetsPolicy()
+ .onRequestedVisibleTypesChanged(embeddedWindow, imeStatsToken);
+ } else {
+ ImeTracker.forLogging().onFailed(imeStatsToken,
+ ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 22c7e8c..24fb207 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -69,7 +69,7 @@
* Note this isn't equal to transition playing, the period should be
* Sync finishNow -> Start transaction apply.
*/
- int mWaitForSyncTransactionCommitCount;
+ boolean mWaitForSyncTransactionCommit;
/**
* For Shell transition.
@@ -112,7 +112,7 @@
public String toString() {
return getClass().getSimpleName() + "{"
+ Integer.toHexString(System.identityHashCode(this))
- + " mWaitForSyncTransactionCommitCount=" + mWaitForSyncTransactionCommitCount
+ + " waitForSyncTransactionCommit=" + mWaitForSyncTransactionCommit
+ " removeAfterTransaction= " + mRemoveAfterTransaction
+ "}";
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3490b3e..a2fda0a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2789,11 +2789,15 @@
@Override
void onDisplayChanged(DisplayContent dc) {
+ final int lastDisplayId = getDisplayId();
super.onDisplayChanged(dc);
if (isLeafTask()) {
final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY;
- mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
- mTaskId, displayId);
+ //Send the callback when the task reparented to another display.
+ if (lastDisplayId != displayId) {
+ mWmService.mAtmService.getTaskChangeNotificationController()
+ .notifyTaskDisplayChanged(mTaskId, displayId);
+ }
}
if (isRootTask()) {
updateSurfaceBounds();
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4eba36f..655a6fb 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2875,19 +2875,12 @@
return out;
}
- // Get the animation theme from the top-most application window
- // when Flags.customAnimationsBehindTranslucent() is false.
final AnimationOptions animOptionsForActivityTransition =
calculateAnimationOptionsForActivityTransition(type, sortedTargets);
-
if (!Flags.moveAnimationOptionsToChange() && animOptionsForActivityTransition != null) {
out.setAnimationOptions(animOptionsForActivityTransition);
}
- // Store the animation options of the topmost non-translucent change
- // (Used when Flags.customAnimationsBehindTranslucent() is true)
- AnimationOptions activityAboveAnimationOptions = null;
-
final ArraySet<WindowContainer> occludedAtEndContainers = new ArraySet<>();
// Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.
final int count = sortedTargets.size();
@@ -3006,26 +2999,9 @@
change.setBackgroundColor(ColorUtils.setAlphaComponent(backgroundColor, 255));
}
- // Calculate the animation options for this change
+ AnimationOptions animOptions = null;
if (Flags.moveAnimationOptionsToChange()) {
- AnimationOptions animOptions = null;
- if (Flags.customAnimationsBehindTranslucent() && activityRecord != null) {
- if (activityAboveAnimationOptions != null) {
- // Inherit the options from one of the changes on top of this
- animOptions = activityAboveAnimationOptions;
- } else {
- // Create the options based on this change's custom animations and layout
- // parameters
- animOptions = getOptions(activityRecord /* customAnimActivity */,
- activityRecord /* animLpActivity */);
- if (!change.hasFlags(FLAG_TRANSLUCENT)) {
- // If this change is not translucent, its options are going to be
- // inherited by the changes below
- activityAboveAnimationOptions = animOptions;
- }
- }
- } else if (activityRecord != null && animOptionsForActivityTransition != null) {
- // Use the same options from the top activity for all the activities
+ if (activityRecord != null && animOptionsForActivityTransition != null) {
animOptions = animOptionsForActivityTransition;
} else if (Flags.activityEmbeddingOverlayPresentationFlag()
&& isEmbeddedTaskFragment) {
@@ -3074,42 +3050,28 @@
@Nullable
private static AnimationOptions calculateAnimationOptionsForActivityTransition(
@TransitionType int type, @NonNull ArrayList<ChangeInfo> sortedTargets) {
+ TransitionInfo.AnimationOptions animOptions = null;
+
+ // Check if the top-most app is an activity (ie. activity->activity). If so, make sure
+ // to honor its custom transition options.
WindowContainer<?> topApp = null;
for (int i = 0; i < sortedTargets.size(); i++) {
- if (!isWallpaper(sortedTargets.get(i).mContainer)) {
- topApp = sortedTargets.get(i).mContainer;
- break;
- }
+ if (isWallpaper(sortedTargets.get(i).mContainer)) continue;
+ topApp = sortedTargets.get(i).mContainer;
+ break;
}
- ActivityRecord animLpActivity = findAnimLayoutParamsActivityRecord(type, sortedTargets);
- return getOptions(topApp.asActivityRecord() /* customAnimActivity */,
- animLpActivity /* animLpActivity */);
- }
-
- /**
- * Updates and returns animOptions with the layout parameters of animLpActivity
- * @param customAnimActivity the activity that drives the custom animation options
- * @param animLpActivity the activity that drives the animation options with its layout
- * parameters
- * @return the options extracted from the provided activities
- */
- @Nullable
- private static AnimationOptions getOptions(@Nullable ActivityRecord customAnimActivity,
- @Nullable ActivityRecord animLpActivity) {
- AnimationOptions animOptions = null;
- // Custom
- if (customAnimActivity != null) {
- animOptions = addCustomActivityTransition(customAnimActivity, true /* open */,
- animOptions);
- animOptions = addCustomActivityTransition(customAnimActivity, false /* open */,
+ if (topApp.asActivityRecord() != null) {
+ final ActivityRecord topActivity = topApp.asActivityRecord();
+ animOptions = addCustomActivityTransition(topActivity, true/* open */,
+ null /* animOptions */);
+ animOptions = addCustomActivityTransition(topActivity, false/* open */,
animOptions);
}
-
- // Layout parameters
+ final ActivityRecord animLpActivity =
+ findAnimLayoutParamsActivityRecord(type, sortedTargets);
final WindowState mainWindow = animLpActivity != null
? animLpActivity.findMainWindow() : null;
- final WindowManager.LayoutParams animLp = mainWindow != null ? mainWindow.mAttrs : null;
-
+ WindowManager.LayoutParams animLp = mainWindow != null ? mainWindow.mAttrs : null;
if (animLp != null && animLp.type != TYPE_APPLICATION_STARTING
&& animLp.windowAnimations != 0) {
// Don't send animation options if no windowAnimations have been set or if the we
@@ -3249,9 +3211,10 @@
return ancestor;
}
- @Nullable
- private static ActivityRecord findAnimLayoutParamsActivityRecord(
- @TransitionType int transit, @NonNull List<ChangeInfo> sortedTargets) {
+ private static ActivityRecord findAnimLayoutParamsActivityRecord(int type,
+ ArrayList<ChangeInfo> sortedTargets) {
+ // Find the layout params of the top-most application window that is part of the
+ // transition, which is what will control the animation theme.
final ArraySet<Integer> activityTypes = new ArraySet<>();
final int targetCount = sortedTargets.size();
for (int i = 0; i < targetCount; ++i) {
@@ -3271,7 +3234,12 @@
// activity through the layout parameter animation style.
return null;
}
+ return findAnimLayoutParamsActivityRecord(sortedTargets, type, activityTypes);
+ }
+ private static ActivityRecord findAnimLayoutParamsActivityRecord(
+ List<ChangeInfo> sortedTargets,
+ @TransitionType int transit, ArraySet<Integer> activityTypes) {
// Remote animations always win, but fullscreen windows override non-fullscreen windows.
ActivityRecord result = lookForTopWindowWithFilter(sortedTargets,
w -> w.getRemoteAnimationDefinition() != null
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 459a509..33f2dd1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1186,9 +1186,13 @@
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
+ // Using SysUI context to have access to Material colors extracted from Wallpaper.
+ final AppCompatConfiguration appCompat = new AppCompatConfiguration(
+ ActivityThread.currentActivityThread().getSystemUiContext());
+
final WindowManagerService wms = main(context, im, showBootMsgs, policy, atm,
new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new,
- SurfaceControl.Builder::new);
+ SurfaceControl.Builder::new, appCompat);
WindowManagerGlobal.setWindowManagerServiceForSystemProcess(wms);
return wms;
}
@@ -1202,12 +1206,14 @@
final boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
DisplayWindowSettingsProvider displayWindowSettingsProvider,
Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<SurfaceControl.Builder> surfaceControlFactory) {
+ Supplier<SurfaceControl.Builder> surfaceControlFactory,
+ AppCompatConfiguration appCompat) {
+
final WindowManagerService[] wms = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(() ->
wms[0] = new WindowManagerService(context, im, showBootMsgs, policy, atm,
displayWindowSettingsProvider, transactionFactory,
- surfaceControlFactory), 0);
+ surfaceControlFactory, appCompat), 0);
return wms[0];
}
@@ -1231,7 +1237,8 @@
boolean showBootMsgs, WindowManagerPolicy policy, ActivityTaskManagerService atm,
DisplayWindowSettingsProvider displayWindowSettingsProvider,
Supplier<SurfaceControl.Transaction> transactionFactory,
- Supplier<SurfaceControl.Builder> surfaceControlFactory) {
+ Supplier<SurfaceControl.Builder> surfaceControlFactory,
+ AppCompatConfiguration appCompat) {
installLock(this, INDEX_WINDOW);
mGlobalLock = atm.getGlobalLock();
mAtmService = atm;
@@ -1283,9 +1290,7 @@
| WindowInsets.Type.navigationBars();
}
- mAppCompatConfiguration = new AppCompatConfiguration(
- // Using SysUI context to have access to Material colors extracted from Wallpaper.
- ActivityThread.currentActivityThread().getSystemUiContext());
+ mAppCompatConfiguration = appCompat;
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b527630..1640ad3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2754,10 +2754,16 @@
* @param outRegion The region to update.
*/
private void updateRegionForModalActivityWindow(Region outRegion) {
- // If the inner bounds of letterbox is available, then it will be used as the
- // touchable region so it won't cover the touchable letterbox and the touch
- // events can slip to activity from letterbox.
- mActivityRecord.getLetterboxInnerBounds(mTmpRect);
+ if (Flags.scrollingFromLetterbox()) {
+ // Touchable region expands to the letterbox area to react to scrolls from letterbox.
+ mTmpRect.setEmpty();
+ } else {
+ // If the activity is letterboxed and scrolling from letterbox is disabled, limit the
+ // touchable region to the activity. This way, the letterbox area is exposed to react
+ // to touch events, and the touch events can slip from the activity from letterbox.
+ mActivityRecord.getLetterboxInnerBounds(mTmpRect);
+ }
+
if (mTmpRect.isEmpty()) {
final Rect transformedBounds = mActivityRecord.getFixedRotationTransformDisplayBounds();
if (transformedBounds != null) {
diff --git a/services/core/java/com/android/server/wm/utils/TEST_MAPPING b/services/core/java/com/android/server/wm/utils/TEST_MAPPING
index aa69d2a..6f34cd0 100644
--- a/services/core/java/com/android/server/wm/utils/TEST_MAPPING
+++ b/services/core/java/com/android/server/wm/utils/TEST_MAPPING
@@ -1,18 +1,7 @@
{
"presubmit": [
{
- "name": "WmTests",
- "options": [
- {
- "include-filter": "com.android.server.wm.utils"
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "WmTests_wm_utils_Presubmit"
}
]
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 67346ab..8c4448e 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -107,6 +107,7 @@
jclass clazz;
jmethodID notifyInputDevicesChanged;
jmethodID notifyTouchpadHardwareState;
+ jmethodID notifyTouchpadGestureInfo;
jmethodID notifySwitch;
jmethodID notifyInputChannelBroken;
jmethodID notifyNoFocusedWindowAnr;
@@ -363,6 +364,7 @@
void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override;
void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs,
int32_t deviceId) override;
+ void notifyTouchpadGestureInfo(enum GestureType type, int32_t deviceId) override;
std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier,
const std::optional<KeyboardLayoutInfo> keyboardLayoutInfo) override;
@@ -996,6 +998,15 @@
checkAndClearExceptionFromCallback(env, "notifyTouchpadHardwareState");
}
+void NativeInputManager::notifyTouchpadGestureInfo(enum GestureType type, int32_t deviceId) {
+ ATRACE_CALL();
+ JNIEnv* env = jniEnv();
+
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyTouchpadGestureInfo, type, deviceId);
+
+ checkAndClearExceptionFromCallback(env, "notifyTouchpadGestureInfo");
+}
+
std::shared_ptr<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier,
const std::optional<KeyboardLayoutInfo> keyboardLayoutInfo) {
@@ -3068,6 +3079,9 @@
"notifyTouchpadHardwareState",
"(Lcom/android/server/input/TouchpadHardwareState;I)V")
+ GET_METHOD_ID(gServiceClassInfo.notifyTouchpadGestureInfo, clazz, "notifyTouchpadGestureInfo",
+ "(II)V")
+
GET_METHOD_ID(gServiceClassInfo.notifySwitch, clazz,
"notifySwitch", "(JII)V");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b6e45fc8..6314b85 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -10625,8 +10625,16 @@
final DevicePolicyData policyData = getUserData(userId);
if (transitionCheckNeeded) {
// Optional state transition check for non-ADB case.
- checkUserProvisioningStateTransition(policyData.mUserProvisioningState,
- newState);
+ try {
+ checkUserProvisioningStateTransition(
+ policyData.mUserProvisioningState,
+ newState);
+
+ } catch (IllegalStateException e) {
+ Slogf.e(LOG_TAG,
+ "Exception caught while changing provisioning state", e);
+ throw e;
+ }
}
policyData.mUserProvisioningState = newState;
saveSettingsLocked(userId);
@@ -10637,6 +10645,10 @@
}
private void checkUserProvisioningStateTransition(int currentState, int newState) {
+ if (Flags.userProvisioningSameState()) {
+ Preconditions.checkState(newState != currentState, "New state cannot"
+ + " be the same as the current state: [" + newState + "]");
+ }
// Valid transitions for normal use-cases.
switch (currentState) {
case DevicePolicyManager.STATE_USER_UNMANAGED:
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 24ee46f..f271162 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -102,9 +102,6 @@
PolicyEnforcerCallbacks.setAutoTimezoneEnabled(value, context),
new BooleanPolicySerializer());
- // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
- // actual policy with the correct arguments (packageName and permission name)
- // when reading the policies from xml.
static final PolicyDefinition<Integer> GENERIC_PERMISSION_GRANT =
new PolicyDefinition<>(
new PackagePermissionPolicyKey(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY),
@@ -123,10 +120,6 @@
PolicyEnforcerCallbacks::setPermissionGrantState,
new IntegerPolicySerializer());
- /**
- * Passing in {@code null} for {@code packageName} or {@code permissionName} will return a
- * {@link #GENERIC_PERMISSION_GRANT}.
- */
static PolicyDefinition<Integer> PERMISSION_GRANT(
@NonNull String packageName, @NonNull String permissionName) {
Objects.requireNonNull(packageName, "packageName must not be null");
@@ -170,9 +163,6 @@
PolicyEnforcerCallbacks::setUserControlDisabledPackages,
new PackageSetPolicySerializer());
- // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
- // actual policy with the correct arguments (i.e. packageName) when reading the policies from
- // xml.
static PolicyDefinition<ComponentName> GENERIC_PERSISTENT_PREFERRED_ACTIVITY =
new PolicyDefinition<>(
new IntentFilterPolicyKey(
@@ -184,10 +174,6 @@
PolicyEnforcerCallbacks::addPersistentPreferredActivity,
new ComponentNamePolicySerializer());
- /**
- * Passing in {@code null} for {@code intentFilter} will return
- * {@link #GENERIC_PERSISTENT_PREFERRED_ACTIVITY}.
- */
static PolicyDefinition<ComponentName> PERSISTENT_PREFERRED_ACTIVITY(
@NonNull IntentFilter intentFilter) {
Objects.requireNonNull(intentFilter, "intentFilter must not be null");
@@ -197,9 +183,6 @@
intentFilter));
}
- // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
- // actual policy with the correct arguments (i.e. packageName) when reading the policies from
- // xml.
static PolicyDefinition<Boolean> GENERIC_PACKAGE_UNINSTALL_BLOCKED =
new PolicyDefinition<>(
new PackagePolicyKey(
@@ -209,10 +192,6 @@
PolicyEnforcerCallbacks::setUninstallBlocked,
new BooleanPolicySerializer());
- /**
- * Passing in {@code null} for {@code packageName} will return
- * {@link #GENERIC_PACKAGE_UNINSTALL_BLOCKED}.
- */
static PolicyDefinition<Boolean> PACKAGE_UNINSTALL_BLOCKED(@NonNull String packageName) {
Objects.requireNonNull(packageName, "packageName must not be null");
return GENERIC_PACKAGE_UNINSTALL_BLOCKED.createPolicyDefinition(
@@ -220,9 +199,6 @@
DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
}
- // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
- // actual policy with the correct arguments (i.e. packageName) when reading the policies from
- // xml.
static PolicyDefinition<Bundle> GENERIC_APPLICATION_RESTRICTIONS =
new PolicyDefinition<>(
new PackagePolicyKey(
@@ -237,10 +213,6 @@
PolicyEnforcerCallbacks::setApplicationRestrictions,
new BundlePolicySerializer());
- /**
- * Passing in {@code null} for {@code packageName} will return
- * {@link #GENERIC_APPLICATION_RESTRICTIONS}.
- */
static PolicyDefinition<Bundle> APPLICATION_RESTRICTIONS(@NonNull String packageName) {
Objects.requireNonNull(packageName, "packageName must not be null");
return GENERIC_APPLICATION_RESTRICTIONS.createPolicyDefinition(
@@ -266,9 +238,6 @@
PolicyEnforcerCallbacks::noOp,
new IntegerPolicySerializer());
- // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
- // actual policy with the correct arguments (i.e. packageName) when reading the policies from
- // xml.
static PolicyDefinition<Boolean> GENERIC_APPLICATION_HIDDEN =
new PolicyDefinition<>(
new PackagePolicyKey(
@@ -281,10 +250,6 @@
PolicyEnforcerCallbacks::setApplicationHidden,
new BooleanPolicySerializer());
- /**
- * Passing in {@code null} for {@code packageName} will return
- * {@link #GENERIC_APPLICATION_HIDDEN}.
- */
static PolicyDefinition<Boolean> APPLICATION_HIDDEN(@NonNull String packageName) {
Objects.requireNonNull(packageName, "packageName must not be null");
return GENERIC_APPLICATION_HIDDEN.createPolicyDefinition(
@@ -292,9 +257,6 @@
DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY, packageName));
}
- // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
- // actual policy with the correct arguments (i.e. packageName) when reading the policies from
- // xml.
static PolicyDefinition<Boolean> GENERIC_ACCOUNT_MANAGEMENT_DISABLED =
new PolicyDefinition<>(
new AccountTypePolicyKey(
@@ -305,10 +267,6 @@
PolicyEnforcerCallbacks::noOp,
new BooleanPolicySerializer());
- /**
- * Passing in {@code null} for {@code accountType} will return
- * {@link #GENERIC_ACCOUNT_MANAGEMENT_DISABLED}.
- */
static PolicyDefinition<Boolean> ACCOUNT_MANAGEMENT_DISABLED(@NonNull String accountType) {
Objects.requireNonNull(accountType, "accountType must not be null");
return GENERIC_ACCOUNT_MANAGEMENT_DISABLED.createPolicyDefinition(
@@ -668,8 +626,6 @@
throw new UnsupportedOperationException("Non-coexistable global policies not supported,"
+ "please add support.");
}
- // TODO: maybe use this instead of manually adding to the map
-// sPolicyDefinitions.put(policyDefinitionKey, this);
}
void saveToXml(TypedXmlSerializer serializer) throws IOException {
diff --git a/services/foldables/devicestateprovider/TEST_MAPPING b/services/foldables/devicestateprovider/TEST_MAPPING
index 47de131..0538381 100644
--- a/services/foldables/devicestateprovider/TEST_MAPPING
+++ b/services/foldables/devicestateprovider/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "foldable-device-state-provider-tests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "foldable-device-state-provider-tests"
}
]
}
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
index 1db9e8d..6393e11 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/Android.bp
@@ -1,7 +1,7 @@
aconfig_declarations {
name: "device_state_flags",
package: "com.android.server.policy.feature.flags",
- container: "system_ext",
+ container: "system",
srcs: [
"device_state_flags.aconfig",
],
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
index f827b55..21e33dd 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/feature/device_state_flags.aconfig
@@ -1,5 +1,5 @@
package: "com.android.server.policy.feature.flags"
-container: "system_ext"
+container: "system"
flag {
name: "enable_dual_display_blocking"
diff --git a/services/incremental/TEST_MAPPING b/services/incremental/TEST_MAPPING
index 4c9403c..cbb9962 100644
--- a/services/incremental/TEST_MAPPING
+++ b/services/incremental/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPackageManagerStatsHostTestCases",
- "options": [
- {
- "include-filter": "com.android.cts.packagemanager.stats.host.PackageInstallerV2StatsTests"
- }
- ]
+ "name": "CtsPackageManagerStatsHostTestCases_host_packageinstallerv2statstests"
},
{
"name": "CtsPackageManagerIncrementalStatsHostTestCases",
diff --git a/services/lint-baseline.xml b/services/lint-baseline.xml
index a311d07..95da56d 100644
--- a/services/lint-baseline.xml
+++ b/services/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
+<issues format="6" by="lint 8.4.0-alpha08" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha08">
<issue
id="SimpleManualPermissionEnforcement"
@@ -8,7 +8,7 @@
errorLine2=" ^">
<location
file="frameworks/base/services/java/com/android/server/SystemConfigService.java"
- line="46"
+ line="50"
column="13"/>
</issue>
@@ -19,7 +19,7 @@
errorLine2=" ^">
<location
file="frameworks/base/services/java/com/android/server/SystemConfigService.java"
- line="54"
+ line="58"
column="13"/>
</issue>
@@ -30,7 +30,7 @@
errorLine2=" ^">
<location
file="frameworks/base/services/java/com/android/server/SystemConfigService.java"
- line="67"
+ line="71"
column="13"/>
</issue>
@@ -41,7 +41,7 @@
errorLine2=" ^">
<location
file="frameworks/base/services/java/com/android/server/SystemConfigService.java"
- line="76"
+ line="80"
column="13"/>
</issue>
@@ -52,8 +52,30 @@
errorLine2=" ^">
<location
file="frameworks/base/services/java/com/android/server/SystemConfigService.java"
- line="107"
+ line="111"
column="13"/>
</issue>
-</issues>
\ No newline at end of file
+ <issue
+ id="SimpleManualPermissionEnforcement"
+ message="ISystemConfig permission check should be converted to @EnforcePermission annotation"
+ errorLine1=" getContext().enforceCallingOrSelfPermission("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/services/java/com/android/server/SystemConfigService.java"
+ line="127"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="SimpleManualPermissionEnforcement"
+ message="ISystemConfig permission check should be converted to @EnforcePermission annotation"
+ errorLine1=" getContext().enforceCallingOrSelfPermission("
+ errorLine2=" ^">
+ <location
+ file="frameworks/base/services/java/com/android/server/SystemConfigService.java"
+ line="137"
+ column="13"/>
+ </issue>
+
+</issues>
diff --git a/services/people/java/com/android/server/people/TEST_MAPPING b/services/people/java/com/android/server/people/TEST_MAPPING
index 55b355c..8677337 100644
--- a/services/people/java/com/android/server/people/TEST_MAPPING
+++ b/services/people/java/com/android/server/people/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.people.data"
- }
- ]
+ "name": "FrameworksServicesTests_people_data"
}
]
}
\ No newline at end of file
diff --git a/services/permission/TEST_MAPPING b/services/permission/TEST_MAPPING
index 4de4a56..af4aaf9 100644
--- a/services/permission/TEST_MAPPING
+++ b/services/permission/TEST_MAPPING
@@ -105,26 +105,10 @@
]
},
{
- "name": "CtsVirtualDevicesAudioTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.virtualdevice.cts.audio.VirtualAudioPermissionTest"
- }
- ]
+ "name": "CtsVirtualDevicesAudioTestCases_audio_virtualaudiopermissiontest"
},
{
- "name": "CtsVirtualDevicesAppLaunchTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "include-filter": "android.virtualdevice.cts.applaunch.VirtualDevicePermissionTest"
- }
- ]
+ "name": "CtsVirtualDevicesAppLaunchTestCases_applaunch_virtualdevicepermissiontest"
}
],
"imports": [
diff --git a/services/print/java/com/android/server/print/TEST_MAPPING b/services/print/java/com/android/server/print/TEST_MAPPING
index 4fa8822..1033b1a 100644
--- a/services/print/java/com/android/server/print/TEST_MAPPING
+++ b/services/print/java/com/android/server/print/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsPrintTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- }
- ]
+ "name": "CtsPrintTestCases_Presubmit"
}
]
}
diff --git a/services/tests/InputMethodSystemServerTests/TEST_MAPPING b/services/tests/InputMethodSystemServerTests/TEST_MAPPING
index de9f771..7313941 100644
--- a/services/tests/InputMethodSystemServerTests/TEST_MAPPING
+++ b/services/tests/InputMethodSystemServerTests/TEST_MAPPING
@@ -1,22 +1,12 @@
{
"presubmit": [
{
- "name": "FrameworksInputMethodSystemServerTests",
- "options": [
- {"include-filter": "com.android.server.inputmethod"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksInputMethodSystemServerTests_server_inputmethod"
}
],
"postsubmit": [
{
- "name": "FrameworksImeTests",
- "options": [
- {"include-filter": "com.android.inputmethodservice"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksImeTests_android_inputmethodservice"
}
]
}
diff --git a/services/tests/PackageManagerServiceTests/TEST_MAPPING b/services/tests/PackageManagerServiceTests/TEST_MAPPING
index 5d96af9..13ba317 100644
--- a/services/tests/PackageManagerServiceTests/TEST_MAPPING
+++ b/services/tests/PackageManagerServiceTests/TEST_MAPPING
@@ -4,21 +4,7 @@
"name": "AppEnumerationInternalTests"
},
{
- "name": "PackageManagerServiceServerTests",
- "options": [
- {
- "include-filter": "com.android.server.pm."
- },
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "PackageManagerServiceServerTests_server_pm_Presubmit"
}
],
"postsubmit": [
@@ -26,21 +12,7 @@
"name": "PackageManagerServiceHostTests"
},
{
- "name": "PackageManagerServiceServerTests",
- "options": [
- {
- "include-filter": "com.android.server.pm."
- },
- {
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "PackageManagerServiceServerTests_server_pm_Postsubmit"
}
],
"kernel-presubmit": [
diff --git a/services/tests/appfunctions/Android.bp b/services/tests/appfunctions/Android.bp
index b5cf986..9560ec9 100644
--- a/services/tests/appfunctions/Android.bp
+++ b/services/tests/appfunctions/Android.bp
@@ -45,8 +45,8 @@
],
libs: [
- "android.test.base",
- "android.test.runner",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
certificate: "platform",
diff --git a/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt b/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
index 650e520..dbbb2fe 100644
--- a/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
+++ b/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionRuntimeMetadataTest.kt
@@ -101,4 +101,15 @@
assertThat(actualPackageName).isEqualTo(expectedPackageName)
}
+
+ @Test
+ fun testBuild() {
+ val runtimeMetadata = AppFunctionRuntimeMetadata.Builder("com.pkg", "funcId").build()
+
+ assertThat(runtimeMetadata.packageName).isEqualTo("com.pkg")
+ assertThat(runtimeMetadata.functionId).isEqualTo("funcId")
+ assertThat(runtimeMetadata.enabled).isNull()
+ assertThat(runtimeMetadata.appFunctionStaticMetadataQualifiedId)
+ .isEqualTo("android\$apps-db/app_functions#com.pkg/funcId")
+ }
}
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt
index edcbb9e..e761e8d 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt
@@ -84,7 +84,7 @@
val schema = session.setSchema(setSchemaRequest)
assertThat(schema.get()).isNotNull()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
@@ -110,7 +110,7 @@
val schema = session.setSchema(setSchemaRequest)
assertThat(schema.get()).isNotNull()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
@@ -144,7 +144,7 @@
val schema = session.setSchema(setSchemaRequest)
assertThat(schema.get()).isNotNull()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
@@ -175,7 +175,7 @@
.build()
session.setSchema(setSchemaRequest).get()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureGlobalSearchSessionTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureGlobalSearchSessionTest.kt
index 38cba65..7fe7263 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureGlobalSearchSessionTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureGlobalSearchSessionTest.kt
@@ -94,8 +94,7 @@
val schema = session.setSchema(setSchemaRequest)
assertThat(schema.get()).isNotNull()
val appFunctionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, TEST_FUNCTION_ID, "")
- .build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, TEST_FUNCTION_ID).build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(appFunctionRuntimeMetadata)
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
index b938c3c..c05c381 100644
--- a/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/MetadataSyncAdapterTest.kt
@@ -16,26 +16,28 @@
package com.android.server.appfunctions
import android.app.appfunctions.AppFunctionRuntimeMetadata
-import android.app.appfunctions.AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema
-import android.app.appfunctions.AppFunctionStaticMetadataHelper
+import android.app.appsearch.AppSearchBatchResult
import android.app.appsearch.AppSearchManager
-import android.app.appsearch.AppSearchManager.SearchContext
+import android.app.appsearch.AppSearchResult
+import android.app.appsearch.AppSearchSchema
import android.app.appsearch.GenericDocument
+import android.app.appsearch.GetByDocumentIdRequest
+import android.app.appsearch.GetSchemaResponse
import android.app.appsearch.PutDocumentsRequest
+import android.app.appsearch.RemoveByDocumentIdRequest
import android.app.appsearch.SearchResult
import android.app.appsearch.SearchSpec
import android.app.appsearch.SetSchemaRequest
+import android.app.appsearch.SetSchemaResponse
import android.util.ArrayMap
import android.util.ArraySet
+import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.infra.AndroidFuture
import com.android.server.appfunctions.FutureAppSearchSession.FutureSearchResults
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors
-import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicBoolean
-import org.junit.After
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -47,46 +49,19 @@
private val testExecutor = MoreExecutors.directExecutor()
private val packageManager = context.packageManager
- @Before
- @After
- fun clearData() {
- val searchContext = SearchContext.Builder(TEST_DB).build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaRequest = SetSchemaRequest.Builder().setForceOverride(true).build()
- it.setSchema(setSchemaRequest).get()
- }
- }
-
@Test
fun getPackageToFunctionIdMap() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+ val searchSession = FakeSearchSession()
val functionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
- val setSchemaRequest =
- SetSchemaRequest.Builder()
- .addSchemas(AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema())
- .addSchemas(
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(TEST_TARGET_PKG_NAME)
- )
- .build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaResponse = it.setSchema(setSchemaRequest).get()
- assertThat(setSchemaResponse).isNotNull()
- val appSearchBatchResult = it.put(putDocumentsRequest).get()
- assertThat(appSearchBatchResult.isSuccess).isTrue()
- }
+ searchSession.put(putDocumentsRequest).get()
- val metadataSyncAdapter =
- MetadataSyncAdapter(
- testExecutor,
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext),
- packageManager,
- )
val packageToFunctionIdMap =
- metadataSyncAdapter.getPackageToFunctionIdMap(
- AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE,
+ MetadataSyncAdapter.getPackageToFunctionIdMap(
+ searchSession,
+ "fakeSchema",
AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME,
)
@@ -97,22 +72,15 @@
@Test
fun getPackageToFunctionIdMap_multipleDocuments() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
+ val searchSession = FakeSearchSession()
val functionRuntimeMetadata =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId", "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
val functionRuntimeMetadata1 =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId1", "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId1").build()
val functionRuntimeMetadata2 =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId2", "").build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId2").build()
val functionRuntimeMetadata3 =
- AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId3", "").build()
- val setSchemaRequest =
- SetSchemaRequest.Builder()
- .addSchemas(AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema())
- .addSchemas(
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(TEST_TARGET_PKG_NAME)
- )
- .build()
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId3").build()
val putDocumentsRequest: PutDocumentsRequest =
PutDocumentsRequest.Builder()
.addGenericDocuments(
@@ -122,21 +90,11 @@
functionRuntimeMetadata3,
)
.build()
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext).use {
- val setSchemaResponse = it.setSchema(setSchemaRequest).get()
- assertThat(setSchemaResponse).isNotNull()
- val appSearchBatchResult = it.put(putDocumentsRequest).get()
- assertThat(appSearchBatchResult.isSuccess).isTrue()
- }
+ searchSession.put(putDocumentsRequest).get()
- val metadataSyncAdapter =
- MetadataSyncAdapter(
- testExecutor,
- FutureAppSearchSessionImpl(appSearchManager, testExecutor, searchContext),
- packageManager,
- )
val packageToFunctionIdMap =
- metadataSyncAdapter.getPackageToFunctionIdMap(
+ MetadataSyncAdapter.getPackageToFunctionIdMap(
+ searchSession,
AppFunctionRuntimeMetadata.RUNTIME_SCHEMA_TYPE,
AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID,
AppFunctionRuntimeMetadata.PROPERTY_PACKAGE_NAME,
@@ -172,66 +130,24 @@
@Test
fun syncMetadata_noDiff() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
- val appSearchSession =
- PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
- val fakeFunctionId = "syncMetadata_noDiff"
- val fakeStaticMetadata: GenericDocument =
- GenericDocument.Builder<GenericDocument.Builder<*>>(
- AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE,
- AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction(
- TEST_TARGET_PKG_NAME,
- fakeFunctionId,
- ),
- AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
- )
- .setPropertyString(
- AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME,
- TEST_TARGET_PKG_NAME,
- )
- .setPropertyString(
- AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
- fakeFunctionId,
- )
- .build()
- appSearchSession.overrideStaticMetadataSearchResult = mutableListOf(fakeStaticMetadata)
- val putCorrespondingSchema =
- appSearchSession
- .setSchema(
- SetSchemaRequest.Builder()
- .addSchemas(
- createParentAppFunctionRuntimeSchema(),
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(
- TEST_TARGET_PKG_NAME
- ),
- )
- .setForceOverride(true)
- .build()
- )
- .get()
- assertThat(putCorrespondingSchema).isNotNull()
- val putCorrespondingRuntimeMetadata =
- appSearchSession
- .put(
- PutDocumentsRequest.Builder()
- .addGenericDocuments(
- AppFunctionRuntimeMetadata.Builder(
- TEST_TARGET_PKG_NAME,
- fakeFunctionId,
- "",
- )
- .build()
- )
- .build()
- )
- .get()
- assertThat(putCorrespondingRuntimeMetadata.isSuccess).isTrue()
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ runtimeSearchSession.put(putDocumentsRequest).get()
+ staticSearchSession.put(putDocumentsRequest).get()
val metadataSyncAdapter =
- MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+ MetadataSyncAdapter(testExecutor, packageManager, appSearchManager)
- val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+ val submitSyncRequest =
+ metadataSyncAdapter.trySyncAppFunctionMetadataBlocking(
+ staticSearchSession,
+ runtimeSearchSession,
+ )
- assertThat(submitSyncRequest.get()).isTrue()
+ assertThat(submitSyncRequest).isInstanceOf(Unit::class.java)
}
@Test
@@ -257,35 +173,23 @@
@Test
fun syncMetadata_addedFunction() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
- val appSearchSession =
- PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
- val fakeFunctionId = "addedFunction1"
- val fakeStaticMetadata: GenericDocument =
- GenericDocument.Builder<GenericDocument.Builder<*>>(
- AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE,
- AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction(
- TEST_TARGET_PKG_NAME,
- fakeFunctionId,
- ),
- AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE,
- )
- .setPropertyString(
- AppFunctionStaticMetadataHelper.PROPERTY_PACKAGE_NAME,
- TEST_TARGET_PKG_NAME,
- )
- .setPropertyString(
- AppFunctionStaticMetadataHelper.PROPERTY_FUNCTION_ID,
- fakeFunctionId,
- )
- .build()
- appSearchSession.overrideStaticMetadataSearchResult = mutableListOf(fakeStaticMetadata)
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ staticSearchSession.put(putDocumentsRequest).get()
val metadataSyncAdapter =
- MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+ MetadataSyncAdapter(testExecutor, packageManager, appSearchManager)
- val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+ val submitSyncRequest =
+ metadataSyncAdapter.trySyncAppFunctionMetadataBlocking(
+ staticSearchSession,
+ runtimeSearchSession,
+ )
- assertThat(submitSyncRequest.get()).isTrue()
+ assertThat(submitSyncRequest).isInstanceOf(Unit::class.java)
}
@Test
@@ -325,47 +229,23 @@
@Test
fun syncMetadata_removedFunction() {
- val searchContext: SearchContext = SearchContext.Builder(TEST_DB).build()
- val appSearchSession =
- PartialFakeFutureAppSearchSession(appSearchManager, testExecutor, searchContext)
- val fakeFunctionId = "syncMetadata_removedFunction"
- val putCorrespondingSchema =
- appSearchSession
- .setSchema(
- SetSchemaRequest.Builder()
- .addSchemas(
- createParentAppFunctionRuntimeSchema(),
- AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema(
- TEST_TARGET_PKG_NAME
- ),
- )
- .setForceOverride(true)
- .build()
- )
- .get()
- assertThat(putCorrespondingSchema).isNotNull()
- val putStaleRuntimeMetadata =
- appSearchSession
- .put(
- PutDocumentsRequest.Builder()
- .addGenericDocuments(
- AppFunctionRuntimeMetadata.Builder(
- TEST_TARGET_PKG_NAME,
- fakeFunctionId,
- "",
- )
- .build()
- )
- .build()
- )
- .get()
- assertThat(putStaleRuntimeMetadata.isSuccess).isTrue()
+ val runtimeSearchSession = FakeSearchSession()
+ val staticSearchSession = FakeSearchSession()
+ val functionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_TARGET_PKG_NAME, "testFunctionId").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder().addGenericDocuments(functionRuntimeMetadata).build()
+ runtimeSearchSession.put(putDocumentsRequest).get()
val metadataSyncAdapter =
- MetadataSyncAdapter(testExecutor, appSearchSession, context.packageManager)
+ MetadataSyncAdapter(testExecutor, packageManager, appSearchManager)
- val submitSyncRequest = metadataSyncAdapter.submitSyncRequest()
+ val submitSyncRequest =
+ metadataSyncAdapter.trySyncAppFunctionMetadataBlocking(
+ staticSearchSession,
+ runtimeSearchSession,
+ )
- assertThat(submitSyncRequest.get()).isTrue()
+ assertThat(submitSyncRequest).isInstanceOf(Unit::class.java)
}
@Test
@@ -426,48 +306,99 @@
const val TEST_TARGET_PKG_NAME = "com.android.frameworks.appfunctionstests"
}
- class PartialFakeFutureAppSearchSession(
- appSearchManager: AppSearchManager,
- executor: Executor,
- appSearchContext: SearchContext,
- ) : FutureAppSearchSessionImpl(appSearchManager, executor, appSearchContext) {
- var overrideStaticMetadataSearchResult: MutableList<GenericDocument> = mutableListOf()
- private val overrideUsed = AtomicBoolean(false)
+ class FakeSearchSession : FutureAppSearchSession {
+ private val schemas: MutableSet<AppSearchSchema> = mutableSetOf()
+ private val genericDocumentMutableMap: MutableMap<String, GenericDocument> = mutableMapOf()
- // Overriding this method to fake searching for static metadata.
- // Static metadata is the source of truth for the metadata sync behaviour since the sync is
- // updating the runtime metadata to match the existing static metadata.
+ override fun close() {
+ Log.d("FakeRuntimeMetadataSearchSession", "Closing session")
+ }
+
+ override fun setSchema(
+ setSchemaRequest: SetSchemaRequest
+ ): AndroidFuture<SetSchemaResponse> {
+ schemas.addAll(setSchemaRequest.schemas)
+ return AndroidFuture.completedFuture(SetSchemaResponse.Builder().build())
+ }
+
+ override fun getSchema(): AndroidFuture<GetSchemaResponse> {
+ val resultBuilder = GetSchemaResponse.Builder()
+ for (schema in schemas) {
+ resultBuilder.addSchema(schema)
+ }
+ return AndroidFuture.completedFuture(resultBuilder.build())
+ }
+
+ override fun put(
+ putDocumentsRequest: PutDocumentsRequest
+ ): AndroidFuture<AppSearchBatchResult<String, Void>> {
+ for (document in putDocumentsRequest.genericDocuments) {
+ genericDocumentMutableMap[document.id] = document
+ }
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, Void>()
+ for (document in putDocumentsRequest.genericDocuments) {
+ batchResultBuilder.setResult(document.id, AppSearchResult.newSuccessfulResult(null))
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
+ override fun remove(
+ removeRequest: RemoveByDocumentIdRequest
+ ): AndroidFuture<AppSearchBatchResult<String, Void>> {
+ for (documentId in removeRequest.ids) {
+ if (!genericDocumentMutableMap.keys.contains(documentId)) {
+ throw IllegalStateException("Document $documentId does not exist")
+ }
+ }
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, Void>()
+ for (id in removeRequest.ids) {
+ batchResultBuilder.setResult(id, AppSearchResult.newSuccessfulResult(null))
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
+ override fun getByDocumentId(
+ getRequest: GetByDocumentIdRequest
+ ): AndroidFuture<AppSearchBatchResult<String, GenericDocument>> {
+ val batchResultBuilder = AppSearchBatchResult.Builder<String, GenericDocument>()
+ for (documentId in getRequest.ids) {
+ if (!genericDocumentMutableMap.keys.contains(documentId)) {
+ throw IllegalStateException("Document $documentId does not exist")
+ }
+ batchResultBuilder.setResult(
+ documentId,
+ AppSearchResult.newSuccessfulResult(genericDocumentMutableMap[documentId]),
+ )
+ }
+ return AndroidFuture.completedFuture(batchResultBuilder.build())
+ }
+
override fun search(
queryExpression: String,
searchSpec: SearchSpec,
): AndroidFuture<FutureSearchResults> {
- if (
- searchSpec.filterSchemas.contains(
- AppFunctionStaticMetadataHelper.STATIC_SCHEMA_TYPE
- )
- ) {
- val futureSearchResults =
- object : FutureSearchResults {
- override fun getNextPage(): AndroidFuture<MutableList<SearchResult>> {
- if (overrideUsed.get()) {
- overrideStaticMetadataSearchResult.clear()
- return AndroidFuture.completedFuture(mutableListOf())
- }
- overrideUsed.set(true)
- return AndroidFuture.completedFuture(
- overrideStaticMetadataSearchResult
- .map {
- SearchResult.Builder(TEST_TARGET_PKG_NAME, TEST_DB)
- .setGenericDocument(it)
- .build()
- }
- .toMutableList()
- )
+ val futureSearchResults =
+ object : FutureSearchResults {
+ val hasNextPage = AtomicBoolean(false)
+
+ override fun getNextPage(): AndroidFuture<MutableList<SearchResult>> {
+ val searchResultMutableList: MutableList<SearchResult> =
+ genericDocumentMutableMap.values
+ .map {
+ SearchResult.Builder(TEST_TARGET_PKG_NAME, TEST_DB)
+ .setGenericDocument(it)
+ .build()
+ }
+ .toMutableList()
+ if (!hasNextPage.get()) {
+ hasNextPage.set(true)
+ return AndroidFuture.completedFuture(searchResultMutableList)
+ } else {
+ return AndroidFuture.completedFuture(mutableListOf())
}
}
- return AndroidFuture.completedFuture(futureSearchResults)
- }
- return super.search(queryExpression, searchSpec)
+ }
+ return AndroidFuture.completedFuture(futureSearchResults)
}
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index d0aec3b..bf5a692 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -75,6 +75,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.internal.app.IBatteryStats;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
@@ -158,6 +159,8 @@
private DisplayManagerFlags mDisplayManagerFlagsMock;
@Mock
private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession;
+ @Mock
+ private IBatteryStats mMockBatteryStats;
@Captor
private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor;
@@ -204,7 +207,8 @@
doAnswer((Answer<Void>) invocationOnMock -> null).when(() ->
SystemProperties.set(anyString(), any()));
- doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService);
+ doAnswer((Answer<IBatteryStats>) invocationOnMock -> mMockBatteryStats)
+ .when(BatteryStatsService::getService);
doAnswer((Answer<Boolean>) invocationOnMock -> false)
.when(ActivityManager::isLowRamDeviceStatic);
@@ -2227,6 +2231,52 @@
verify(mHolder.brightnessSetting).saveIfNeeded();
}
+ @Test
+ public void testBatteryStatNotes_enabledOnDefaultDisplayWhenDisabledOnOthers()
+ throws Exception {
+ when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(false);
+
+ verifyNoteScreenState(Display.DEFAULT_DISPLAY, /* expectNote= */ true);
+ }
+
+ @Test
+ public void testBatteryStatNotes_enabledOnDefaultDisplayWhenEnabledOnOthers() throws Exception {
+ when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
+
+ verifyNoteScreenState(Display.DEFAULT_DISPLAY, /* expectNote= */ true);
+ }
+
+ @Test
+ public void testBatteryStatNotes_flagGuardedOnNonDefaultDisplays() throws Exception {
+ when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(false);
+
+ verifyNoteScreenState(/* displayId= */ 2, /* expectNote= */ false);
+
+ when(mDisplayManagerFlagsMock.isBatteryStatsEnabledForAllDisplays()).thenReturn(true);
+
+ verifyNoteScreenState(/* displayId= */ 2, /* expectNote= */ true);
+ }
+
+ private void verifyNoteScreenState(int displayId, boolean expectNote) throws Exception {
+ mHolder = createDisplayPowerController(displayId, UNIQUE_ID);
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ if (expectNote) {
+ verify(mMockBatteryStats)
+ .noteScreenState(
+ displayId, Display.STATE_ON, Display.STATE_REASON_DEFAULT_POLICY);
+ verify(mMockBatteryStats).noteScreenBrightness(eq(displayId), anyInt());
+ } else {
+ verify(mMockBatteryStats, never()).noteScreenState(anyInt(), anyInt(), anyInt());
+ verify(mMockBatteryStats, never()).noteScreenBrightness(anyInt(), anyInt());
+ }
+ }
+
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
diff --git a/services/tests/dreamservicetests/TEST_MAPPING b/services/tests/dreamservicetests/TEST_MAPPING
index a644ea6..38d7000 100644
--- a/services/tests/dreamservicetests/TEST_MAPPING
+++ b/services/tests/dreamservicetests/TEST_MAPPING
@@ -1,21 +1,12 @@
{
"presubmit": [
{
- "name": "DreamServiceTests",
- "options": [
- {"include-filter": "com.android.server.dreams"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "DreamServiceTests_server_dreams"
}
],
"postsubmit": [
{
- "name": "DreamServiceTests",
- "options": [
- {"include-filter": "com.android.server.dreams"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "DreamServiceTests_server_dreams"
}
]
}
diff --git a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
index 8bdfc50..1211456 100644
--- a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
+++ b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
@@ -346,14 +346,16 @@
.thenReturn(mAvailableAudioDeviceInfos.toArray(new AudioDeviceInfo[0]));
}
- private static AudioDeviceAttributes createAudioDeviceAttribute(int type) {
+ private static AudioDeviceAttributes createAudioDeviceAttribute(
+ @AudioDeviceInfo.AudioDeviceType int type) {
// Address is unused.
return new AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT, type, /* address= */ "");
}
private static AudioDeviceInfo createAudioDeviceInfo(
- int type, @NonNull String name, @NonNull String address) {
+ @AudioDeviceInfo.AudioDeviceType int type, @NonNull String name,
+ @NonNull String address) {
return new AudioDeviceInfo(AudioDevicePort.createForTesting(type, name, address));
}
}
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus
new file mode 100644
index 0000000..8b0fab8
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus
@@ -0,0 +1 @@
+0-1
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus
new file mode 100644
index 0000000..40c7bb2
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus
@@ -0,0 +1 @@
+0-3
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
index 2fbe8aa..3fe038a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.res.AssetManager;
+import android.util.IntArray;
import android.util.Log;
import android.util.SparseArray;
@@ -48,6 +49,7 @@
private static final String TAG = CpuInfoReaderTest.class.getSimpleName();
private static final String ROOT_DIR_NAME = "CpuInfoReaderTest";
private static final String VALID_CPUSET_DIR = "valid_cpuset";
+ private static final String VALID_CPUSET_2_DIR = "valid_cpuset_2";
private static final String VALID_CPUSET_WITH_EMPTY_CPUS = "valid_cpuset_with_empty_cpus";
private static final String VALID_CPUFREQ_WITH_EMPTY_AFFECTED_CPUS =
"valid_cpufreq_with_empty_affected_cpus";
@@ -88,54 +90,95 @@
}
@Test
+ public void testReadCpuInfoWithUpdatedCpuset() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithUpdatedCpusetBeforeStopSignal() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ // When stopping the periodic cpuset reading, the reader will create a new snapshot.
+ cpuInfoReader.stopPeriodicCpusetReading();
+ // Any cpuset update after the stop signal should be ignored by the reader.
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+
+ @Test
+ public void testReadCpuInfoWithUpdatedCpusetAfterStopSignal() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.stopPeriodicCpusetReading();
+ // Any cpuset update after the stop signal should be ignored by the reader.
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot();
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+ @Test
public void testReadCpuInfoWithTimeInState() throws Exception {
CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
- SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>();
- expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
- /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
- /* normalizedAvailableCpuFreqKHz= */ 2_402_267,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
- /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
- /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
- /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970,
- /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
- /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
- /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
- /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
- /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
- /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
- /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
- /* normalizedAvailableCpuFreqKHz= */ 1_901_608,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
- /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
- /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
- /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130,
- /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
- /* normalizedAvailableCpuFreqKHz= */ 1_907_125,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
- /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
- /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
- /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970,
- /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
@@ -144,49 +187,7 @@
actualCpuInfos = cpuInfoReader.readCpuInfos();
- expectedCpuInfos.clear();
- expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_600_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
- /* normalizedAvailableCpuFreqKHz= */ 2_525_919,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
- /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
- /* irqTimeMillis= */ 1_400_000, /* softirqTimeMillis= */ 80_000,
- /* stealTimeMillis= */ 21_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
- /* maxCpuFreqKHz= */ 2_900_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
- /* normalizedAvailableCpuFreqKHz= */ 2_503_009,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
- /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
- /* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000,
- /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
- /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
- /* normalizedAvailableCpuFreqKHz= */ 1_788_209,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
- /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
- /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
- /* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000,
- /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ false, /* curCpuFreqKHz= */ MISSING_FREQUENCY,
- /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
- /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
- /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
- /* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000,
- /* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot();
compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
}
@@ -592,4 +593,108 @@
}
return rootDir.delete();
}
+
+ private SparseArray<CpuInfoReader.CpuInfo> getFirstCpuInfosWithTimeInStateSnapshot() {
+ SparseArray<CpuInfoReader.CpuInfo> cpuInfos = new SparseArray<>();
+ cpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
+ /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
+ /* normalizedAvailableCpuFreqKHz= */ 2_402_267,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
+ /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
+ /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
+ /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970,
+ /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
+ /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
+ /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
+ /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
+ /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
+ /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
+ /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+ /* normalizedAvailableCpuFreqKHz= */ 1_901_608,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
+ /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
+ /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
+ /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130,
+ /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+ /* normalizedAvailableCpuFreqKHz= */ 1_907_125,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
+ /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
+ /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
+ /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970,
+ /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ return cpuInfos;
+ }
+
+ private SparseArray<CpuInfoReader.CpuInfo> getSecondCpuInfosWithTimeInStateSnapshot() {
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ return getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+ }
+
+ private SparseArray<CpuInfoReader.CpuInfo> getSecondCpuInfosWithTimeInStateSnapshot(
+ IntArray cpusetCategories) {
+ SparseArray<CpuInfoReader.CpuInfo> cpuInfos = new SparseArray<>();
+ cpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, cpusetCategories.get(0),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_600_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
+ /* normalizedAvailableCpuFreqKHz= */ 2_525_919,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
+ /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
+ /* irqTimeMillis= */ 1_400_000, /* softirqTimeMillis= */ 80_000,
+ /* stealTimeMillis= */ 21_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, cpusetCategories.get(1),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
+ /* maxCpuFreqKHz= */ 2_900_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
+ /* normalizedAvailableCpuFreqKHz= */ 2_503_009,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
+ /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
+ /* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000,
+ /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, cpusetCategories.get(2),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
+ /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
+ /* normalizedAvailableCpuFreqKHz= */ 1_788_209,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
+ /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
+ /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
+ /* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000,
+ /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, cpusetCategories.get(3),
+ /* isOnline= */ false,
+ /* curCpuFreqKHz= */ MISSING_FREQUENCY, /* maxCpuFreqKHz= */ 2_100_000,
+ /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+ /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
+ /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
+ /* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000,
+ /* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ return cpuInfos;
+ }
+
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
index 994313f..d9e09d8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
@@ -26,6 +26,7 @@
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP;
import static com.android.server.cpu.CpuMonitorService.DEFAULT_MONITORING_INTERVAL_MILLISECONDS;
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -75,6 +76,7 @@
private static final long TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS = 100;
private static final long TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS = 150;
private static final long TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS = 300;
+ private static final long TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS = 0;
private static final CpuAvailabilityMonitoringConfig TEST_MONITORING_CONFIG_ALL_CPUSET =
new CpuAvailabilityMonitoringConfig.Builder(CPUSET_ALL)
.addThreshold(30).addThreshold(70).build();
@@ -119,7 +121,8 @@
mService = new CpuMonitorService(mMockContext, mMockCpuInfoReader, mServiceHandlerThread,
/* shouldDebugMonitor= */ true, TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS,
TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS,
- TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
doNothing().when(() -> ServiceManager.addService(eq("cpu_monitor"), any(Binder.class),
anyBoolean(), anyInt()));
@@ -535,6 +538,18 @@
}
@Test
+ public void testBootCompleted() throws Exception {
+ mService.onBootPhase(PHASE_BOOT_COMPLETED);
+
+ // Message to stop periodic cpuset reading is posted on the service handler thread. Sync
+ // with this thread before proceeding.
+ syncWithHandler(mServiceHandler, /* delayMillis= */ 0);
+
+ verify(mMockCpuInfoReader, timeout(ASYNC_CALLBACK_WAIT_TIMEOUT_MILLISECONDS))
+ .stopPeriodicCpusetReading();
+ }
+
+ @Test
public void testHeavyCpuLoadMonitoring() throws Exception {
// TODO(b/267500110): Once heavy CPU load detection logic is added, add unittest.
}
@@ -567,7 +582,8 @@
mServiceHandlerThread, /* shouldDebugMonitor= */ false,
TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS,
TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS,
- TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
startService();
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
index 127d3e8..7ac7aca 100644
--- a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
@@ -39,9 +39,9 @@
],
libs: [
- "android.test.mock",
- "android.test.base",
- "android.test.runner",
+ "android.test.mock.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
jni_libs: [
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
index a82658b..3062d51 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundUserSoundNotifierTest.java
@@ -16,13 +16,19 @@
package com.android.server.pm;
+import static android.media.AudioAttributes.USAGE_ALARM;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.testng.AssertJUnit.assertEquals;
import android.app.Notification;
import android.app.NotificationManager;
@@ -31,6 +37,9 @@
import android.media.AudioAttributes;
import android.media.AudioFocusInfo;
import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
+import android.media.PlayerProxy;
+import android.media.audiopolicy.AudioPolicy;
import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -45,6 +54,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
@RunWith(JUnit4.class)
public class BackgroundUserSoundNotifierTest {
@@ -63,7 +76,10 @@
MockitoAnnotations.initMocks(this);
mSpiedContext = spy(mRealContext);
mUsersToRemove = new ArraySet<>();
- mUserManager = UserManager.get(mRealContext);
+
+ mUserManager = spy(mSpiedContext.getSystemService(UserManager.class));
+ doReturn(mUserManager)
+ .when(mSpiedContext).getSystemService(UserManager.class);
doReturn(mNotificationManager)
.when(mSpiedContext).getSystemService(NotificationManager.class);
mBackgroundUserSoundNotifier = new BackgroundUserSoundNotifier(mSpiedContext);
@@ -74,12 +90,9 @@
mUsersToRemove.stream().toList().forEach(this::removeUser);
}
@Test
- public void testAlarmOnBackgroundUser_ForegroundUserNotified() throws RemoteException {
- AudioAttributes aa = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_ALARM).build();
- UserInfo user = createUser("User",
- UserManager.USER_TYPE_FULL_SECONDARY,
- 0);
+ public void testAlarmOnBackgroundUser_foregroundUserNotified() throws RemoteException {
+ AudioAttributes aa = new AudioAttributes.Builder().setUsage(USAGE_ALARM).build();
+ UserInfo user = createUser("User", UserManager.USER_TYPE_FULL_SECONDARY, 0);
final int fgUserId = mSpiedContext.getUserId();
final int bgUserUid = user.id * 100000;
doReturn(UserHandle.of(fgUserId)).when(mSpiedContext).getUser();
@@ -95,10 +108,9 @@
}
@Test
- public void testMediaOnBackgroundUser_ForegroundUserNotNotified() throws RemoteException {
+ public void testMediaOnBackgroundUser_foregroundUserNotNotified() throws RemoteException {
AudioAttributes aa = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA).build();
- UserInfo user = createUser("User", UserManager.USER_TYPE_FULL_SECONDARY, 0);
final int bgUserUid = mSpiedContext.getUserId() * 100000;
AudioFocusInfo afi = new AudioFocusInfo(aa, bgUserUid, "",
/* packageName= */ "com.android.car.audio", AudioManager.AUDIOFOCUS_GAIN,
@@ -109,9 +121,9 @@
}
@Test
- public void testAlarmOnForegroundUser_ForegroundUserNotNotified() throws RemoteException {
+ public void testAlarmOnForegroundUser_foregroundUserNotNotified() throws RemoteException {
AudioAttributes aa = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_ALARM).build();
+ .setUsage(USAGE_ALARM).build();
final int fgUserId = mSpiedContext.getUserId();
final int fgUserUid = fgUserId * 100000;
doReturn(UserHandle.of(fgUserId)).when(mSpiedContext).getUser();
@@ -123,6 +135,109 @@
verifyZeroInteractions(mNotificationManager);
}
+ @Test
+ public void testMuteAlarmSounds() {
+ final int fgUserId = mSpiedContext.getUserId();
+ int bgUserId = fgUserId + 1;
+ int bgUserUid = bgUserId * 100000;
+ mBackgroundUserSoundNotifier.mNotificationClientUid = bgUserUid;
+
+ AudioManager mockAudioManager = mock(AudioManager.class);
+ when(mSpiedContext.getSystemService(AudioManager.class)).thenReturn(mockAudioManager);
+
+ AudioPlaybackConfiguration apc1 = mock(AudioPlaybackConfiguration.class);
+ when(apc1.getClientUid()).thenReturn(bgUserUid);
+ when(apc1.getPlayerProxy()).thenReturn(mock(PlayerProxy.class));
+
+ AudioPlaybackConfiguration apc2 = mock(AudioPlaybackConfiguration.class);
+ when(apc2.getClientUid()).thenReturn(bgUserUid + 1);
+ when(apc2.getPlayerProxy()).thenReturn(mock(PlayerProxy.class));
+
+ List<AudioPlaybackConfiguration> configs = new ArrayList<>();
+ configs.add(apc1);
+ configs.add(apc2);
+ when(mockAudioManager.getActivePlaybackConfigurations()).thenReturn(configs);
+
+ AudioPolicy mockAudioPolicy = mock(AudioPolicy.class);
+
+ AudioAttributes aa = new AudioAttributes.Builder().setUsage(USAGE_ALARM).build();
+ AudioFocusInfo afi = new AudioFocusInfo(aa, bgUserUid, "", /* packageName= */ "",
+ AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_NONE, /* flags= */ 0,
+ Build.VERSION.SDK_INT);
+ Stack<AudioFocusInfo> focusStack = new Stack<>();
+ focusStack.add(afi);
+ doReturn(focusStack).when(mockAudioPolicy).getFocusStack();
+ mBackgroundUserSoundNotifier.mFocusControlAudioPolicy = mockAudioPolicy;
+
+ mBackgroundUserSoundNotifier.muteAlarmSounds(mSpiedContext);
+
+ verify(apc1.getPlayerProxy()).stop();
+ verify(apc2.getPlayerProxy(), never()).stop();
+ }
+
+ @Test
+ public void testOnAudioFocusGrant_alarmOnBackgroundUser_notifiesForegroundUser() {
+ final int fgUserId = mSpiedContext.getUserId();
+ UserInfo bgUser = createUser("Background User", UserManager.USER_TYPE_FULL_SECONDARY, 0);
+ int bgUserUid = bgUser.id * 100000;
+
+ AudioAttributes aa = new AudioAttributes.Builder().setUsage(USAGE_ALARM).build();
+ AudioFocusInfo afi = new AudioFocusInfo(aa, bgUserUid, "", "",
+ AudioManager.AUDIOFOCUS_GAIN, 0, 0, Build.VERSION.SDK_INT);
+
+ mBackgroundUserSoundNotifier.getAudioPolicyFocusListener()
+ .onAudioFocusGrant(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+
+ verify(mNotificationManager)
+ .notifyAsUser(eq(BackgroundUserSoundNotifier.class.getSimpleName()),
+ eq(afi.getClientUid()), any(Notification.class),
+ eq(UserHandle.of(fgUserId)));
+ }
+
+
+ @Test
+ public void testCreateNotification_UserSwitcherEnabled_bothActionsAvailable() {
+ String userName = "BgUser";
+
+ doReturn(true).when(mUserManager).isUserSwitcherEnabled();
+ doReturn(UserManager.SWITCHABILITY_STATUS_OK)
+ .when(mUserManager).getUserSwitchability(any());
+
+ Notification notification = mBackgroundUserSoundNotifier.createNotification(userName,
+ mSpiedContext);
+
+ assertEquals("Alarm for BgUser", notification.extras.getString(
+ Notification.EXTRA_TITLE));
+ assertEquals(Notification.CATEGORY_REMINDER, notification.category);
+ assertEquals(Notification.VISIBILITY_PUBLIC, notification.visibility);
+ assertEquals(com.android.internal.R.drawable.ic_audio_alarm,
+ notification.getSmallIcon().getResId());
+
+ assertEquals(2, notification.actions.length);
+ assertEquals(mSpiedContext.getString(
+ com.android.internal.R.string.bg_user_sound_notification_button_mute),
+ notification.actions[0].title);
+ assertEquals(mSpiedContext.getString(
+ com.android.internal.R.string.bg_user_sound_notification_button_switch_user),
+ notification.actions[1].title);
+ }
+
+ @Test
+ public void testCreateNotification_UserSwitcherDisabled_onlyMuteActionAvailable() {
+ String userName = "BgUser";
+
+ doReturn(false).when(mUserManager).isUserSwitcherEnabled();
+ doReturn(UserManager.SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED)
+ .when(mUserManager).getUserSwitchability(any());
+
+ Notification notification = mBackgroundUserSoundNotifier.createNotification(userName,
+ mSpiedContext);
+
+ assertEquals(1, notification.actions.length);
+ assertEquals(mSpiedContext.getString(
+ com.android.internal.R.string.bg_user_sound_notification_button_mute),
+ notification.actions[0].title);
+ }
private UserInfo createUser(String name, String userType, int flags) {
UserInfo user = mUserManager.createUser(name, userType, flags);
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/TEST_MAPPING b/services/tests/mockingservicestests/src/com/android/server/rollback/TEST_MAPPING
index 4ac4484..ef2d605 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/TEST_MAPPING
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "RollbackPackageHealthObserverTests",
- "options": [
- {
- "include-filter": "com.android.server.rollback"
- }
- ]
+ "name": "RollbackPackageHealthObserverTests_server_rollback"
}
]
}
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 1a398c5..e0c393c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -100,6 +100,7 @@
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
+import com.android.server.pm.UserManagerInternal;
import org.junit.After;
import org.junit.Before;
@@ -145,6 +146,7 @@
private static final String URI_SCHEME_PACKAGE = "package";
private static final int TEST_USER_ID = 50;
+ private static final int TEST_VISIBLE_BACKGROUND_USER_ID = 51;
private static final UserInfo TEST_USER =
new UserInfo(TEST_USER_ID, "user", UserInfo.FLAG_FULL);
private static final int PARENT_USER_ID = 60;
@@ -170,6 +172,7 @@
private @Mock KeyStoreAuthorization mKeyStoreAuthorization;
private @Mock LockPatternUtils mLockPatternUtils;
private @Mock LockSettingsInternal mLockSettingsInternal;
+ private @Mock UserManagerInternal mUserManagerInternal;
private @Mock PackageManager mPackageManager;
private @Mock UserManager mUserManager;
private @Mock IWindowManager mWindowManager;
@@ -224,6 +227,7 @@
when(mUserManager.getAliveUsers()).thenReturn(List.of(TEST_USER));
when(mUserManager.getEnabledProfileIds(TEST_USER_ID)).thenReturn(new int[0]);
when(mUserManager.getUserInfo(TEST_USER_ID)).thenReturn(TEST_USER);
+ when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(false);
when(mWindowManager.isKeyguardLocked()).thenReturn(true);
@@ -593,6 +597,54 @@
verify(mTrustListener, never()).onTrustManagedChanged(anyBoolean(), anyInt());
}
+ @Test
+ public void testDeviceLocked_visibleBackgroundUser_userLocked() throws RemoteException {
+ setupVisibleBackgroundUser(/* visible= */ true, /* unlocked= */ false);
+ mService.waitForIdle();
+ mTrustManager.reportEnabledTrustAgentsChanged(TEST_VISIBLE_BACKGROUND_USER_ID);
+ mService.waitForIdle();
+ assertThat(mService.isDeviceLockedInner(TEST_VISIBLE_BACKGROUND_USER_ID)).isTrue();
+ }
+
+ @Test
+ public void testDeviceLocked_visibleBackgroundUser_userUnlocked() throws RemoteException {
+ setupVisibleBackgroundUser(/* visible= */ true, /* unlocked= */ true);
+ mService.waitForIdle();
+ mTrustManager.reportEnabledTrustAgentsChanged(TEST_VISIBLE_BACKGROUND_USER_ID);
+ mService.waitForIdle();
+ assertThat(mService.isDeviceLockedInner(TEST_VISIBLE_BACKGROUND_USER_ID)).isFalse();
+ }
+
+ @Test
+ public void testDeviceLocked_invisibleBackgroundUser_userUnlocked() throws RemoteException {
+ setupVisibleBackgroundUser(/* visible= */ false, /* unlocked= */ true);
+ mService.waitForIdle();
+ mTrustManager.reportEnabledTrustAgentsChanged(TEST_VISIBLE_BACKGROUND_USER_ID);
+ mService.waitForIdle();
+ assertThat(mService.isDeviceLockedInner(TEST_VISIBLE_BACKGROUND_USER_ID)).isTrue();
+ }
+
+ private void setupVisibleBackgroundUser(boolean visible, boolean unlocked) {
+ UserInfo info = new UserInfo(TEST_VISIBLE_BACKGROUND_USER_ID, "visible bg user",
+ UserInfo.FLAG_FULL);
+
+ when(mActivityManager.isUserRunning(TEST_VISIBLE_BACKGROUND_USER_ID)).thenReturn(true);
+
+ when(mLockPatternUtils.isSecure(TEST_VISIBLE_BACKGROUND_USER_ID)).thenReturn(true);
+
+ when(mUserManager.getAliveUsers()).thenReturn(List.of(TEST_USER, info));
+ when(mUserManager.getEnabledProfileIds(TEST_VISIBLE_BACKGROUND_USER_ID)).thenReturn(
+ new int[0]);
+ when(mUserManager.getUserInfo(TEST_VISIBLE_BACKGROUND_USER_ID)).thenReturn(info);
+ when(mUserManager.isUserUnlocked(TEST_VISIBLE_BACKGROUND_USER_ID)).thenReturn(unlocked);
+ when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true);
+
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, mUserManagerInternal);
+ when(mUserManagerInternal.isVisibleBackgroundFullUser(
+ TEST_VISIBLE_BACKGROUND_USER_ID)).thenReturn(visible);
+ }
+
private void setUpRenewableTrust(ITrustAgentService trustAgent) throws RemoteException {
ITrustAgentServiceCallback callback = getCallback(trustAgent);
callback.setManagingTrust(true);
diff --git a/services/tests/ondeviceintelligencetests/Android.bp b/services/tests/ondeviceintelligencetests/Android.bp
index aa85942..a31a3fb 100644
--- a/services/tests/ondeviceintelligencetests/Android.bp
+++ b/services/tests/ondeviceintelligencetests/Android.bp
@@ -47,9 +47,9 @@
],
libs: [
- "android.test.mock",
- "android.test.base",
- "android.test.runner",
+ "android.test.mock.stubs.system",
+ "android.test.base.stubs.system",
+ "android.test.runner.stubs.system",
],
certificate: "platform",
diff --git a/services/tests/performancehinttests/Android.bp b/services/tests/performancehinttests/Android.bp
index 1692921c..c8121fc 100644
--- a/services/tests/performancehinttests/Android.bp
+++ b/services/tests/performancehinttests/Android.bp
@@ -19,7 +19,7 @@
"truth",
],
libs: [
- "android.test.base",
+ "android.test.base.stubs.system",
],
test_suites: [
"automotive-tests",
diff --git a/services/tests/powerstatstests/TEST_MAPPING b/services/tests/powerstatstests/TEST_MAPPING
index 1e8d2de..d3d3cf6 100644
--- a/services/tests/powerstatstests/TEST_MAPPING
+++ b/services/tests/powerstatstests/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "PowerStatsTests",
- "options": [
- {"include-filter": "com.android.server.power.stats"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "PowerStatsTests_power_stats"
}
],
"ravenwood-presubmit": [
@@ -20,11 +15,7 @@
],
"postsubmit": [
{
- "name": "PowerStatsTests",
- "options": [
- {"include-filter": "com.android.server.power.stats"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "PowerStatsTests_power_stats"
}
]
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
index f74cfae..c0be865 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java
@@ -56,14 +56,14 @@
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{300_000_000},
new int[]{Display.STATE_ON}, 0);
- stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
- 30 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_DOZE, Display.STATE_REASON_DEFAULT_POLICY,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{200_000_000},
new int[]{Display.STATE_DOZE}, 30 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
- 120 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_DEFAULT_POLICY,
+ 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{100_000_000},
new int[]{Display.STATE_OFF}, 120 * MINUTE_IN_MS);
@@ -93,37 +93,37 @@
final int[] screenStates = new int[] {Display.STATE_OFF, Display.STATE_OFF};
- stats.noteScreenStateLocked(0, screenStates[0], 0, 0, 0);
- stats.noteScreenStateLocked(1, screenStates[1], 0, 0, 0);
+ stats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN, 0, 0, 0);
+ stats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN, 0, 0, 0);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{300, 400}, screenStates, 0);
// Switch display0 to doze
screenStates[0] = Display.STATE_DOZE;
- stats.noteScreenStateLocked(0, screenStates[0], 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
- 30 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{200, 300},
screenStates, 30 * MINUTE_IN_MS);
// Switch display1 to doze
screenStates[1] = Display.STATE_DOZE;
- stats.noteScreenStateLocked(1, Display.STATE_DOZE, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS,
- 90 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, Display.STATE_DOZE, Display.STATE_REASON_UNKNOWN,
+ 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS);
// 100,000,000 uC should be attributed to display 0 doze here.
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{100_000_000, 700_000_000},
screenStates, 90 * MINUTE_IN_MS);
// Switch display0 to off
screenStates[0] = Display.STATE_OFF;
- stats.noteScreenStateLocked(0, screenStates[0], 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
- 120 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN,
+ 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS);
// 40,000,000 and 70,000,000 uC should be attributed to display 0 and 1 doze here.
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{40_000_000, 70_000_000},
screenStates, 120 * MINUTE_IN_MS);
// Switch display1 to off
screenStates[1] = Display.STATE_OFF;
- stats.noteScreenStateLocked(1, screenStates[1], 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS,
- 150 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN,
+ 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS);
stats.updateDisplayEnergyConsumerStatsLocked(new long[]{100, 90_000_000}, screenStates,
150 * MINUTE_IN_MS);
// 90,000,000 uC should be attributed to display 1 doze here.
@@ -148,10 +148,10 @@
public void testPowerProfileBasedModel() {
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
- stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
- 30 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
- 120 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_DOZE, Display.STATE_REASON_UNKNOWN,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS);
AmbientDisplayPowerCalculator calculator =
new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());
@@ -174,15 +174,15 @@
BatteryStatsImpl stats = mStatsRule.getBatteryStats();
- stats.noteScreenStateLocked(1, Display.STATE_OFF, 0, 0, 0);
- stats.noteScreenStateLocked(0, Display.STATE_DOZE, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS,
- 30 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(1, Display.STATE_DOZE, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS,
- 90 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(0, Display.STATE_OFF, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS,
- 120 * MINUTE_IN_MS);
- stats.noteScreenStateLocked(1, Display.STATE_OFF, 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS,
- 150 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN, 0, 0, 0);
+ stats.noteScreenStateLocked(0, Display.STATE_DOZE, Display.STATE_REASON_UNKNOWN,
+ 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, Display.STATE_DOZE, Display.STATE_REASON_UNKNOWN,
+ 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS, 90 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS, 120 * MINUTE_IN_MS);
+ stats.noteScreenStateLocked(1, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS, 150 * MINUTE_IN_MS);
AmbientDisplayPowerCalculator calculator =
new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile());
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
index afbe9159..2ccb642 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java
@@ -44,6 +44,10 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.platform.test.ravenwood.RavenwoodRule;
import android.telephony.AccessNetworkConstants;
import android.telephony.ActivityStatsTechSpecificInfo;
@@ -65,6 +69,7 @@
import com.android.internal.os.MonotonicClock;
import com.android.internal.os.PowerProfile;
import com.android.internal.power.EnergyConsumerStats;
+import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.BatteryStatsImpl.DualTimer;
import org.junit.Rule;
@@ -90,6 +95,8 @@
.setProvideMainThread(true)
.build();
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final String TAG = BatteryStatsNoteTest.class.getSimpleName();
private static final int UID = 10500;
@@ -104,6 +111,54 @@
@Mock
NetworkStatsManager mNetworkStatsManager;
+ @DisabledOnRavenwood
+ @EnableFlags(Flags.FLAG_BATTERY_STATS_SCREEN_STATE_EVENT)
+ @Test
+ public void testScreenStateEvent_screenStateEventFlagOn_eventsRecorded() throws Exception {
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClock());
+ bi.forceRecordAllHistory();
+
+ bi.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_DEFAULT_POLICY,
+ 0, 0, 0);
+ bi.noteScreenStateLocked(2, Display.STATE_DOZE_SUSPEND, Display.STATE_REASON_DRAW_WAKE_LOCK,
+ 1, 1, 1);
+
+ BatteryStatsHistoryIterator iterator =
+ bi.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
+ BatteryStats.HistoryItem item =
+ iterateAndFind(iterator, HistoryItem.EVENT_DISPLAY_STATE_CHANGED);
+ assertThat(item).isNotNull();
+ assertThat(item.eventTag).isNotNull();
+ assertThat(item.eventTag.string).isEqualTo("display=0 state=ON reason=DEFAULT_POLICY");
+ assertThat(item.eventTag.uid).isEqualTo(Process.INVALID_UID);
+
+ item = iterateAndFind(iterator, HistoryItem.EVENT_DISPLAY_STATE_CHANGED);
+ assertThat(item).isNotNull();
+ assertThat(item.eventTag).isNotNull();
+ assertThat(item.eventTag.string)
+ .isEqualTo("display=2 state=DOZE_SUSPEND reason=DRAW_WAKE_LOCK");
+ assertThat(item.eventTag.uid).isEqualTo(Process.INVALID_UID);
+
+ // Last check to make sure that we did not record any extra event.
+ assertThat(iterateAndFind(iterator, HistoryItem.EVENT_DISPLAY_STATE_CHANGED)).isNull();
+ }
+
+ @DisableFlags(Flags.FLAG_BATTERY_STATS_SCREEN_STATE_EVENT)
+ @Test
+ public void testScreenStateEvent_screenStateEventFlagOff_eventsNotRecorded() throws Exception {
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClock());
+ bi.forceRecordAllHistory();
+
+ bi.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_DEFAULT_POLICY,
+ 0, 0, 0);
+ bi.noteScreenStateLocked(2, Display.STATE_DOZE_SUSPEND, Display.STATE_REASON_DRAW_WAKE_LOCK,
+ 1, 1, 1);
+
+ BatteryStatsHistoryIterator iterator =
+ bi.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
+ assertThat(iterateAndFind(iterator, HistoryItem.EVENT_DISPLAY_STATE_CHANGED)).isNull();
+ }
+
/**
* Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked.
*/
@@ -285,20 +340,15 @@
final BatteryStatsHistoryIterator iterator =
bi.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
- BatteryStats.HistoryItem item;
+ BatteryStats.HistoryItem item =
+ iterateAndFind(iterator, HistoryItem.EVENT_LONG_WAKE_LOCK_START);
- while ((item = iterator.next()) != null) {
- if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_START) break;
- }
- assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_START);
+ assertThat(item).isNotNull();
assertThat(item.eventTag).isNotNull();
assertThat(item.eventTag.string).isEqualTo(historyName);
assertThat(item.eventTag.uid).isEqualTo(UID);
- while ((item = iterator.next()) != null) {
- if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH) break;
- }
- assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
+ item = iterateAndFind(iterator, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
assertThat(item.eventTag).isNotNull();
assertThat(item.eventTag.string).isEqualTo(historyName);
assertThat(item.eventTag.uid).isEqualTo(UID);
@@ -343,20 +393,15 @@
final BatteryStatsHistoryIterator iterator =
bi.iterateBatteryStatsHistory(0, MonotonicClock.UNDEFINED);
- BatteryStats.HistoryItem item;
-
- while ((item = iterator.next()) != null) {
- if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_START) break;
- }
- assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_START);
+ BatteryStats.HistoryItem item =
+ iterateAndFind(iterator, HistoryItem.EVENT_LONG_WAKE_LOCK_START);
+ assertThat(item).isNotNull();
assertThat(item.eventTag).isNotNull();
assertThat(item.eventTag.string).isEqualTo(historyName);
assertThat(item.eventTag.uid).isEqualTo(UID);
- while ((item = iterator.next()) != null) {
- if (item.eventCode == HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH) break;
- }
- assertThat(item.eventCode).isEqualTo(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
+ item = iterateAndFind(iterator, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH);
+ assertThat(item).isNotNull();
assertThat(item.eventTag).isNotNull();
assertThat(item.eventTag.string).isEqualTo(historyName);
assertThat(item.eventTag.uid).isEqualTo(UID);
@@ -2562,4 +2607,18 @@
currentTimeMs, currentTimeMs, mNetworkStatsManager);
}
}
+
+ /**
+ * Moves a given {@link BatteryStatsHistoryIterator} until a history item with the given
+ * {@code eventCode} is found and returns the history item. Returns {@code null} if no such item
+ * is found.
+ */
+ private static BatteryStats.HistoryItem iterateAndFind(
+ BatteryStatsHistoryIterator iterator, int eventCode) {
+ BatteryStats.HistoryItem item;
+ while ((item = iterator.next()) != null) {
+ if (item.eventCode == eventCode) return item;
+ }
+ return null;
+ }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
index 88d4ea7..2da98e8 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/ScreenPowerCalculatorTest.java
@@ -61,7 +61,8 @@
mStatsRule.initMeasuredEnergyStatsLocked();
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
- batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0);
+ batteryStats.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{0},
new int[]{Display.STATE_ON}, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true,
@@ -79,7 +80,7 @@
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{300_000_000},
new int[]{Display.STATE_ON}, 60 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(0, Display.STATE_OFF,
+ batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
@@ -150,8 +151,10 @@
final int[] screenStates = new int[]{Display.STATE_ON, Display.STATE_OFF};
- batteryStats.noteScreenStateLocked(0, screenStates[0], 0, 0, 0);
- batteryStats.noteScreenStateLocked(1, screenStates[1], 0, 0, 0);
+ batteryStats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
+ batteryStats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true, 0, 0);
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{300, 400}, screenStates, 0);
@@ -166,10 +169,10 @@
screenStates[0] = Display.STATE_OFF;
screenStates[1] = Display.STATE_ON;
- batteryStats.noteScreenStateLocked(0, screenStates[0],
+ batteryStats.noteScreenStateLocked(0, screenStates[0], Display.STATE_REASON_UNKNOWN,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(1, screenStates[1], 80 * MINUTE_IN_MS,
- 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
+ batteryStats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN,
+ 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{600_000_000, 500},
screenStates, 80 * MINUTE_IN_MS);
@@ -178,8 +181,8 @@
batteryStats.noteScreenBrightnessLocked(1, 75, 98 * MINUTE_IN_MS, 98 * MINUTE_IN_MS);
screenStates[1] = Display.STATE_OFF;
- batteryStats.noteScreenStateLocked(1, screenStates[1], 110 * MINUTE_IN_MS,
- 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
+ batteryStats.noteScreenStateLocked(1, screenStates[1], Display.STATE_REASON_UNKNOWN,
+ 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
batteryStats.updateDisplayEnergyConsumerStatsLocked(new long[]{700, 800_000_000},
screenStates, 110 * MINUTE_IN_MS);
@@ -240,7 +243,8 @@
public void testPowerProfileBasedModel() {
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
- batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0);
+ batteryStats.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true,
0, 0);
@@ -253,7 +257,7 @@
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true,
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(0, Display.STATE_OFF,
+ batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
@@ -313,8 +317,10 @@
BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
- batteryStats.noteScreenStateLocked(0, Display.STATE_ON, 0, 0, 0);
- batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, 0, 0, 0);
+ batteryStats.noteScreenStateLocked(0, Display.STATE_ON, Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
+ batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 0, 0, 0);
batteryStats.noteScreenBrightnessLocked(0, 255, 0, 0);
setProcState(APP_UID1, ActivityManager.PROCESS_STATE_TOP, true,
0, 0);
@@ -327,16 +333,16 @@
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP, true,
20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(0, Display.STATE_OFF,
+ batteryStats.noteScreenStateLocked(0, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(1, Display.STATE_ON, 80 * MINUTE_IN_MS,
- 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
+ batteryStats.noteScreenStateLocked(1, Display.STATE_ON, Display.STATE_REASON_UNKNOWN,
+ 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(1, 20, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(1, 250, 86 * MINUTE_IN_MS, 86 * MINUTE_IN_MS);
batteryStats.noteScreenBrightnessLocked(1, 75, 98 * MINUTE_IN_MS, 98 * MINUTE_IN_MS);
- batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, 110 * MINUTE_IN_MS,
- 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
+ batteryStats.noteScreenStateLocked(1, Display.STATE_OFF, Display.STATE_REASON_UNKNOWN,
+ 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
setProcState(APP_UID2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, false,
110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS);
diff --git a/services/tests/selinux/Android.bp b/services/tests/selinux/Android.bp
index 12a7038..048978a 100644
--- a/services/tests/selinux/Android.bp
+++ b/services/tests/selinux/Android.bp
@@ -42,9 +42,9 @@
"mockito_extended",
],
libs: [
- "android.test.base",
- "android.test.mock",
- "android.test.runner",
+ "android.test.base.stubs.system",
+ "android.test.mock.stubs.system",
+ "android.test.runner.stubs.system",
"servicestests-core-utils",
],
static_libs: [
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index b41b30c..bbe0755 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -91,6 +91,7 @@
"net_flags_lib",
"CtsVirtualDeviceCommonLib",
"com_android_server_accessibility_flags_lib",
+ "locksettings_flags_lib",
],
libs: [
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 95a7f4b..a0005d9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -25,6 +25,7 @@
import static com.android.server.hdmi.HdmiCecLocalDevicePlayback.STANDBY_AFTER_ACTIVE_SOURCE_LOST_DELAY_MS;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_BOOT_UP;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+import static com.android.server.hdmi.PowerStatusMonitorActionFromPlayback.MONITORING_INTERVAL_MS;
import static com.google.common.truth.Truth.assertThat;
@@ -145,6 +146,11 @@
protected void sendBroadcastAsUser(@RequiresPermission Intent intent) {
// do nothing
}
+
+ @Override
+ protected boolean isHdmiControlEnhancedBehaviorFlagEnabled() {
+ return true;
+ }
};
mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context));
@@ -2556,6 +2562,44 @@
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(unexpectedMessage);
}
+ @Test
+ public void powerStatusMonitorActionFromPlayback_TvReportPowerOff_goToSleep() {
+ mHdmiControlService.onWakeUp(HdmiControlService.WAKE_UP_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.getActions(
+ PowerStatusMonitorActionFromPlayback.class)).hasSize(1);
+ assertThat(mPowerManager.isInteractive()).isTrue();
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage givePowerStatus =
+ HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mPlaybackLogicalAddress,
+ Constants.ADDR_TV);
+ HdmiCecMessage reportPowerStatusTvOn =
+ HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV, mPlaybackLogicalAddress,
+ HdmiControlManager.POWER_STATUS_ON);
+ HdmiCecMessage reportPowerStatusTvStandby =
+ HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV, mPlaybackLogicalAddress,
+ HdmiControlManager.POWER_STATUS_STANDBY);
+
+ assertThat(mNativeWrapper.getResultMessages().contains(givePowerStatus)).isTrue();
+ mNativeWrapper.onCecMessage(reportPowerStatusTvOn);
+ mTestLooper.dispatchAll();
+
+ assertThat(mPowerManager.isInteractive()).isTrue();
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(MONITORING_INTERVAL_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(mNativeWrapper.getResultMessages().contains(givePowerStatus)).isTrue();
+ mNativeWrapper.onCecMessage(reportPowerStatusTvStandby);
+ mTestLooper.dispatchAll();
+
+ assertThat(mPowerManager.isInteractive()).isFalse();
+ }
+
private void skipActiveSourceLostUi(long idleDuration) {
mTestLooper.moveTimeForward(POPUP_AFTER_ACTIVE_SOURCE_LOST_DELAY_MS);
mTestLooper.dispatchAll();
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
index 58f5bb3..9b23b49 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/TEST_MAPPING
@@ -6,23 +6,7 @@
],
"postsubmit": [
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.location.contexthub."
- },
- {
- // I believe this include annotation is preventing tests from being run
- // as there are no matching tests with the Postsubmit annotation.
- "include-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "FrameworksServicesTests_com_android_server_location_contexthub"
}
]
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index d6f7e21..d071c15 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -60,6 +60,9 @@
import android.os.ServiceSpecificException;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -70,6 +73,7 @@
import com.android.server.pm.UserManagerInternal;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -108,6 +112,9 @@
0x26, 0x52, 0x72, 0x63, 0x63, 0x61, 0x78, 0x23,
};
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
private Context mContext;
private UserManager mUserManager;
private UserManagerInternal mUserManagerInternal;
@@ -145,7 +152,6 @@
private RebootEscrowProviderInterface mRebootEscrowProviderInUse;
private ConnectivityManager.NetworkCallback mNetworkCallback;
private Consumer<ConnectivityManager.NetworkCallback> mNetworkConsumer;
- private boolean mWaitForInternet;
MockInjector(
Context context,
@@ -159,7 +165,6 @@
super(context, storage, userManagerInternal);
mRebootEscrow = rebootEscrow;
mServerBased = false;
- mWaitForInternet = false;
RebootEscrowProviderHalImpl.Injector halInjector =
new RebootEscrowProviderHalImpl.Injector() {
@Override
@@ -185,7 +190,6 @@
super(context, storage, userManagerInternal);
mRebootEscrow = null;
mServerBased = true;
- mWaitForInternet = false;
RebootEscrowProviderServerBasedImpl.Injector injector =
new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) {
@Override
@@ -227,15 +231,6 @@
}
@Override
- public boolean waitForInternet() {
- return mWaitForInternet;
- }
-
- public void setWaitForNetwork(boolean waitForNetworkEnabled) {
- mWaitForInternet = waitForNetworkEnabled;
- }
-
- @Override
public boolean isNetworkConnected() {
return false;
}
@@ -934,10 +929,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternet_success()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -987,10 +982,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForInternetRemoteException_Failure()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1042,10 +1037,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkUnavailable()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1090,9 +1085,9 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkLost() throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1145,10 +1140,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_networkAvailableWithDelay()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1204,10 +1199,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_waitForInternet_timeoutExhausted()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1264,10 +1259,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_serverBasedWaitForNetwork_retryCountExhausted()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
@@ -1320,10 +1315,10 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_WAIT_FOR_INTERNET_ROR)
public void loadRebootEscrowDataIfAvailable_ServerBasedWaitForInternet_RetrySuccess()
throws Exception {
setServerBasedRebootEscrowProvider();
- mMockInjector.setWaitForNetwork(true);
when(mInjected.getBootCount()).thenReturn(0);
RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
diff --git a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
index 944c1df..dc3b144 100644
--- a/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
+++ b/services/tests/servicestests/src/com/android/server/om/TEST_MAPPING
@@ -4,12 +4,7 @@
"name": "FrameworksServicesTests_om"
},
{
- "name": "PackageManagerServiceHostTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.test.OverlayActorVisibilityTest"
- }
- ]
+ "name": "PackageManagerServiceHostTests_test_overlayactorvisibilitytest"
}
]
}
diff --git a/services/tests/servicestests/src/com/android/server/supervision/OWNERS b/services/tests/servicestests/src/com/android/server/supervision/OWNERS
new file mode 100644
index 0000000..a5de8007
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/supervision/OWNERS
@@ -0,0 +1 @@
+include /services/supervision/OWNERS
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
index b97a268..585df84 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java
@@ -2465,6 +2465,7 @@
final String pkg = "package";
final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+ String expectedTriggeringKey = null;
// Post singleton groups, above forced group limit
for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT; i++) {
NotificationRecord summary = getNotificationRecord(pkg, i,
@@ -2473,15 +2474,67 @@
NotificationRecord child = getNotificationRecord(pkg, i + 42,
String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp "+i, false);
notificationList.add(child);
+ expectedTriggeringKey = child.getKey();
summaryByGroup.put(summary.getGroupKey(), summary);
mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
summary.isCanceled = true; // simulate removing the app summary
mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
-
}
// Check that notifications are forced grouped
- verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(),
- eq(expectedGroupKey), anyInt(), eq(getNotificationAttributes(BASE_FLAGS)));
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg),
+ eq(expectedTriggeringKey), eq(expectedGroupKey), anyInt(),
+ eq(getNotificationAttributes(BASE_FLAGS)));
+ verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
+ eq(expectedGroupKey), eq(true));
+ verify(mCallback, never()).removeAutoGroup(anyString());
+ verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString());
+ verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(),
+ any());
+
+ // Check that summaries are canceled
+ verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).removeAppProvidedSummary(
+ anyString());
+ }
+
+ @Test
+ @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING,
+ Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS})
+ public void testAddAggregateSummary_summaryTriggers_singletonGroups() {
+ final List<NotificationRecord> notificationList = new ArrayList<>();
+ final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>();
+ final String pkg = "package";
+ final String expectedGroupKey = GroupHelper.getFullAggregateGroupKey(pkg,
+ AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier());
+ final int firstChildIdx = 1;
+ // Post singleton groups, below forced group limit
+ for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT - 1; i++) {
+ NotificationRecord summary = getNotificationRecord(pkg, i,
+ String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true);
+ notificationList.add(summary);
+ NotificationRecord child = getNotificationRecord(pkg, i + 42,
+ String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + i, false);
+ notificationList.add(child);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+ mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup);
+ }
+
+ // Post triggering group summary
+ final String expectedTriggeringKey = notificationList.get(firstChildIdx).getKey();
+ final int triggerIdx = AUTOGROUP_SINGLETONS_AT_COUNT - 1;
+ NotificationRecord summary = getNotificationRecord(pkg, triggerIdx,
+ String.valueOf(triggerIdx), UserHandle.SYSTEM, "testGrp " + triggerIdx, true);
+ notificationList.add(summary);
+ NotificationRecord child = getNotificationRecord(pkg, triggerIdx + 42,
+ String.valueOf(triggerIdx + 42), UserHandle.SYSTEM, "testGrp " + triggerIdx, false);
+ notificationList.add(child);
+ summaryByGroup.put(summary.getGroupKey(), summary);
+ mGroupHelper.onNotificationPostedWithDelay(summary, notificationList, summaryByGroup);
+
+ // Check that notifications are forced grouped
+ verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg),
+ eq(expectedTriggeringKey), eq(expectedGroupKey), anyInt(),
+ eq(getNotificationAttributes(BASE_FLAGS)));
verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(),
eq(expectedGroupKey), eq(true));
verify(mCallback, never()).removeAutoGroup(anyString());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index f8ff1f4..84c4f62 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -32,6 +32,7 @@
import static android.service.notification.Condition.STATE_TRUE;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.service.notification.ZenModeConfig.XML_VERSION_MODES_API;
+import static android.service.notification.ZenModeConfig.XML_VERSION_MODES_UI;
import static android.service.notification.ZenModeConfig.ZEN_TAG;
import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_DEACTIVATE;
import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_NONE;
@@ -756,7 +757,7 @@
assertEquals("a", fromXml.getPkg());
fromXml.condition = new Condition(Uri.EMPTY, "", Condition.STATE_TRUE);
- assertTrue(fromXml.isAutomaticActive());
+ assertTrue(fromXml.isActive());
}
@Test
@@ -1169,6 +1170,23 @@
assertThat(suppressedEffectsOf(result)).isEqualTo(suppressedEffectsOf(policy));
}
+ @Test
+ public void readXml_fixesWronglyDisabledManualRule() throws Exception {
+ ZenModeConfig config = getCustomConfig();
+ if (!Flags.modesUi()) {
+ config.manualRule = new ZenModeConfig.ZenRule();
+ config.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ }
+ config.manualRule.enabled = false;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ writeConfigXml(config, XML_VERSION_MODES_UI, /* forBackup= */ false, baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ZenModeConfig fromXml = readConfigXml(bais);
+
+ assertThat(fromXml.manualRule.enabled).isTrue();
+ }
+
private static String suppressedEffectsOf(Policy policy) {
return suppressedEffectsToString(policy.suppressedVisualEffects) + "("
+ policy.suppressedVisualEffects + ")";
@@ -1274,7 +1292,7 @@
out.setOutput(new BufferedOutputStream(os), "utf-8");
out.startDocument(null, true);
out.startTag(null, tag);
- ZenModeConfig.writeRuleXml(rule, out);
+ ZenModeConfig.writeRuleXml(rule, out, /* forBackup= */ false);
out.endTag(null, tag);
out.endDocument();
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index baa633f..9b87947 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -5788,7 +5788,7 @@
// ... but it is NOT active
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(newRuleId);
- assertThat(storedRule.isAutomaticActive()).isFalse();
+ assertThat(storedRule.isActive()).isFalse();
assertThat(storedRule.isTrueOrUnknown()).isFalse();
assertThat(storedRule.condition).isNull();
assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
@@ -5841,7 +5841,7 @@
// ... but it is NEITHER active NOR snoozed.
ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(newRuleId);
- assertThat(storedRule.isAutomaticActive()).isFalse();
+ assertThat(storedRule.isActive()).isFalse();
assertThat(storedRule.isTrueOrUnknown()).isFalse();
assertThat(storedRule.condition).isNull();
assertThat(storedRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
@@ -6619,7 +6619,7 @@
new Condition(rule.getConditionId(), "manual-on", STATE_TRUE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
assertThat(zenRule.condition).isNull();
@@ -6627,14 +6627,14 @@
new Condition(rule.getConditionId(), "manual-off", STATE_FALSE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isNull();
// Bonus check: app has resumed control over the rule and can now turn it on.
mZenModeHelper.setAutomaticZenRuleState(ruleId, autoOn, ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isEqualTo(autoOn);
}
@@ -6655,7 +6655,7 @@
mZenModeHelper.setAutomaticZenRuleState(ruleId, autoOn, ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isEqualTo(autoOn);
@@ -6663,7 +6663,7 @@
new Condition(rule.getConditionId(), "manual-off", STATE_FALSE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
assertThat(zenRule.condition).isEqualTo(autoOn);
@@ -6671,14 +6671,14 @@
new Condition(rule.getConditionId(), "manual-on", STATE_TRUE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isEqualTo(autoOn);
// Bonus check: app has resumed control over the rule and can now turn it off.
mZenModeHelper.setAutomaticZenRuleState(ruleId, autoOff, ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRule.condition).isEqualTo(autoOff);
}
@@ -6696,7 +6696,7 @@
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
ZenRule zenRuleOn = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRuleOn.isAutomaticActive()).isTrue();
+ assertThat(zenRuleOn.isActive()).isTrue();
assertThat(zenRuleOn.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
assertThat(zenRuleOn.condition).isNotNull();
@@ -6704,7 +6704,7 @@
new Condition(rule.getConditionId(), "manual-off", STATE_FALSE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
ZenRule zenRuleOff = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRuleOff.isAutomaticActive()).isFalse();
+ assertThat(zenRuleOff.isActive()).isFalse();
assertThat(zenRuleOff.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
assertThat(zenRuleOff.condition).isNotNull();
}
@@ -6723,27 +6723,27 @@
new Condition(rule.getConditionId(), "manual-on", STATE_TRUE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-off", STATE_FALSE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-off", STATE_FALSE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
}
@Test
@@ -6760,35 +6760,35 @@
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-off", STATE_FALSE, SOURCE_USER_ACTION),
ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-off", STATE_FALSE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isFalse();
+ assertThat(zenRule.isActive()).isFalse();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
ORIGIN_APP, CUSTOM_PKG_UID);
zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
- assertThat(zenRule.isAutomaticActive()).isTrue();
+ assertThat(zenRule.isActive()).isTrue();
assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
@@ -6805,14 +6805,14 @@
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-on-from-sysui", STATE_TRUE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isTrue();
+ assertThat(getZenRule(ruleId).isActive()).isTrue();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
// ... and they can turn it off manually from inside the app.
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-off-from-app", STATE_FALSE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isFalse();
+ assertThat(getZenRule(ruleId).isActive()).isFalse();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
@@ -6829,21 +6829,21 @@
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-on-from-app", STATE_TRUE,
SOURCE_SCHEDULE), ORIGIN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isTrue();
+ assertThat(getZenRule(ruleId).isActive()).isTrue();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
// User manually turns off rule from SysUI / Settings...
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-off-from-sysui", STATE_FALSE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isFalse();
+ assertThat(getZenRule(ruleId).isActive()).isFalse();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
// ... and they can turn it on manually from inside the app.
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-on-from-app", STATE_TRUE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isTrue();
+ assertThat(getZenRule(ruleId).isActive()).isTrue();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
@@ -6861,14 +6861,14 @@
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "manual-on-from-app", STATE_TRUE,
SOURCE_USER_ACTION), ORIGIN_USER_IN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isTrue();
+ assertThat(getZenRule(ruleId).isActive()).isTrue();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
// ... so the app can turn it off when its schedule is over.
mZenModeHelper.setAutomaticZenRuleState(ruleId,
new Condition(rule.getConditionId(), "auto-off-from-app", STATE_FALSE,
SOURCE_SCHEDULE), ORIGIN_APP, CUSTOM_PKG_UID);
- assertThat(getZenRule(ruleId).isAutomaticActive()).isFalse();
+ assertThat(getZenRule(ruleId).isActive()).isFalse();
assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE);
}
@@ -6923,6 +6923,75 @@
assertThat(eventsRule.triggerDescription).isNotEmpty();
}
+ @Test
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void setAutomaticZenRuleState_withManualActivation_activeOnReboot()
+ throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
+ .setPackage(mPkg)
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mPkg, rule, ORIGIN_APP, "adding",
+ CUSTOM_PKG_UID);
+ mZenModeHelper.setAutomaticZenRuleState(ruleId,
+ new Condition(rule.getConditionId(), "manual-on", STATE_TRUE, SOURCE_USER_ACTION),
+ ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
+ assertThat(mZenModeHelper.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
+ ZenRule zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
+ assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
+ assertThat(zenRule.condition).isNull();
+
+ ByteArrayOutputStream xmlBytes = writeXmlAndPurge(ZenModeConfig.XML_VERSION_MODES_UI);
+ zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
+ assertThat(zenRule).isNull();
+
+ // Now simulate a reboot -> reload the configuration after purging.
+ TypedXmlPullParser parser = getParserForByteStream(xmlBytes);
+ mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ if (Flags.modesUi()) {
+ assertThat(mZenModeHelper.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
+ zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
+ assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_ACTIVATE);
+ assertThat(zenRule.condition).isNull();
+ } else {
+ assertThat(mZenModeHelper.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
+ }
+ }
+
+ @Test
+ @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI})
+ public void setAutomaticZenRuleState_withManualDeactivation_clearedOnReboot()
+ throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Rule", Uri.parse("cond"))
+ .setPackage(mPkg)
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mPkg, rule, ORIGIN_APP, "adding",
+ CUSTOM_PKG_UID);
+ mZenModeHelper.setAutomaticZenRuleState(ruleId,
+ new Condition(rule.getConditionId(), "auto-on", STATE_TRUE, SOURCE_CONTEXT),
+ ORIGIN_APP, CUSTOM_PKG_UID);
+ mZenModeHelper.setAutomaticZenRuleState(ruleId,
+ new Condition(rule.getConditionId(), "snooze", STATE_FALSE, SOURCE_USER_ACTION),
+ ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID);
+ assertThat(mZenModeHelper.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE);
+ ZenRule zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
+ assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_DEACTIVATE);
+ assertThat(zenRule.condition).isNotNull();
+
+ ByteArrayOutputStream xmlBytes = writeXmlAndPurge(ZenModeConfig.XML_VERSION_MODES_UI);
+ zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
+ assertThat(zenRule).isNull();
+
+ // Now simulate a reboot -> reload the configuration after purging.
+ TypedXmlPullParser parser = getParserForByteStream(xmlBytes);
+ mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
+
+ assertThat(mZenModeHelper.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE);
+ zenRule = mZenModeHelper.mConfig.automaticRules.get(ruleId);
+ assertThat(zenRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE);
+ assertThat(zenRule.condition).isNotNull();
+ }
+
private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode,
@Nullable ZenPolicy zenPolicy) {
ZenRule rule = new ZenRule();
diff --git a/services/tests/vibrator/TEST_MAPPING b/services/tests/vibrator/TEST_MAPPING
index 39bd238..b17b96a 100644
--- a/services/tests/vibrator/TEST_MAPPING
+++ b/services/tests/vibrator/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksVibratorServicesTests",
- "options": [
- {"exclude-annotation": "androidx.test.filters.FlakyTest"},
- {"exclude-annotation": "androidx.test.filters.LargeTest"},
- {"exclude-annotation": "org.junit.Ignore"}
- ]
+ "name": "FrameworksVibratorServicesTests"
}
],
"postsubmit": [
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
index 6076d33..f7127df 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
@@ -18,6 +18,7 @@
import static android.os.VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
import static android.os.VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
+import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK;
import static android.os.VibrationAttributes.USAGE_IME_FEEDBACK;
import static android.os.VibrationAttributes.USAGE_TOUCH;
import static android.os.VibrationEffect.Composition.PRIMITIVE_CLICK;
@@ -105,7 +106,7 @@
@Before
public void setUp() {
- mSetFlagsRule.enableFlags(FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED);
+ mSetFlagsRule.disableFlags(FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED);
}
@Test
@@ -398,7 +399,7 @@
HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
for (int effectId : BIOMETRIC_FEEDBACK_CONSTANTS) {
- VibrationAttributes attrs = provider.getVibrationAttributesForHapticFeedback(
+ VibrationAttributes attrs = provider.getVibrationAttributes(
effectId, /* flags */ 0, /* privFlags */ 0);
assertThat(attrs.getUsage()).isEqualTo(VibrationAttributes.USAGE_COMMUNICATION_REQUEST);
}
@@ -408,7 +409,7 @@
public void testVibrationAttribute_forNotBypassingIntensitySettings() {
HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
- VibrationAttributes attrs = provider.getVibrationAttributesForHapticFeedback(
+ VibrationAttributes attrs = provider.getVibrationAttributes(
SAFE_MODE_ENABLED, /* flags */ 0, /* privFlags */ 0);
assertThat(attrs.isFlagSet(FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)).isFalse();
@@ -418,7 +419,7 @@
public void testVibrationAttribute_forByassingIntensitySettings() {
HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
- VibrationAttributes attrs = provider.getVibrationAttributesForHapticFeedback(
+ VibrationAttributes attrs = provider.getVibrationAttributes(
SAFE_MODE_ENABLED,
/* flags */ HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING, /* privFlags */ 0);
@@ -431,7 +432,7 @@
HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
- VibrationAttributes attrs = provider.getVibrationAttributesForHapticFeedback(
+ VibrationAttributes attrs = provider.getVibrationAttributes(
effectId, /* flags */ 0, /* privFlags */ 0);
assertWithMessage("Expected FLAG_BYPASS_INTERRUPTION_POLICY for effect " + effectId)
.that(attrs.isFlagSet(FLAG_BYPASS_INTERRUPTION_POLICY)).isTrue();
@@ -444,7 +445,7 @@
HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
- VibrationAttributes attrs = provider.getVibrationAttributesForHapticFeedback(
+ VibrationAttributes attrs = provider.getVibrationAttributes(
effectId, /* flags */ 0, /* privFlags */ 0);
assertWithMessage("Expected no FLAG_BYPASS_INTERRUPTION_POLICY for effect " + effectId)
.that(attrs.isFlagSet(FLAG_BYPASS_INTERRUPTION_POLICY)).isFalse();
@@ -452,11 +453,64 @@
}
@Test
+ public void testVibrationAttribute_scrollFeedback_inputCustomizedFlag_useTouchUsage() {
+ mSetFlagsRule.enableFlags(FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED);
+ HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
+
+ for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
+ VibrationAttributes attrs = provider.getVibrationAttributes(effectId, /* flags */
+ 0, /* privFlags */ 0);
+ assertWithMessage("Expected USAGE_TOUCH for scroll effect " + effectId
+ + ", if no input customization").that(attrs.getUsage()).isEqualTo(USAGE_TOUCH);
+ }
+ }
+
+ @Test
+ public void testVibrationAttribute_scrollFeedback_noInputCustomizedFlag_useHardwareFeedback() {
+ HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
+
+ for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
+ VibrationAttributes attrs = provider.getVibrationAttributes(effectId, /* flags */
+ 0, /* privFlags */ 0);
+ assertWithMessage("Expected USAGE_HARDWARE_FEEDBACK for scroll effect " + effectId
+ + ", if no input customization").that(attrs.getUsage()).isEqualTo(
+ USAGE_HARDWARE_FEEDBACK);
+ }
+ }
+
+ @Test
+ public void testVibrationAttribute_scrollFeedback_rotaryInputSource_useHardwareFeedback() {
+ mSetFlagsRule.enableFlags(FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED);
+ HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
+
+ for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
+ VibrationAttributes attrs = provider.getVibrationAttributes(
+ effectId, InputDevice.SOURCE_ROTARY_ENCODER, /* flags */ 0, /* privFlags */ 0);
+ assertWithMessage(
+ "Expected USAGE_HARDWARE_FEEDBACK for input source SOURCE_ROTARY_ENCODER").that(
+ attrs.getUsage()).isEqualTo(USAGE_HARDWARE_FEEDBACK);
+ }
+ }
+
+ @Test
+ public void testVibrationAttribute_scrollFeedback_touchInputSource_useTouchUsage() {
+ mSetFlagsRule.enableFlags(FLAG_HAPTIC_FEEDBACK_INPUT_SOURCE_CUSTOMIZATION_ENABLED);
+ HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
+
+ for (int effectId : SCROLL_FEEDBACK_CONSTANTS) {
+ VibrationAttributes attrs = provider.getVibrationAttributes(
+ effectId, InputDevice.SOURCE_TOUCHSCREEN, /* flags */ 0, /* privFlags */ 0);
+ assertWithMessage("Expected USAGE_TOUCH for input source SOURCE_TOUCHSCREEN").that(
+ attrs.getUsage()).isEqualTo(USAGE_TOUCH);
+ }
+ }
+
+ @Test
public void testVibrationAttribute_notIme_useTouchUsage() {
HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
- VibrationAttributes attrs = provider.getVibrationAttributesForHapticFeedback(
+ VibrationAttributes attrs = provider.getVibrationAttributes(
effectId, /* flags */ 0, /* privFlags */ 0);
assertWithMessage("Expected USAGE_TOUCH for effect " + effectId)
.that(attrs.getUsage()).isEqualTo(USAGE_TOUCH);
@@ -468,7 +522,7 @@
HapticFeedbackVibrationProvider provider = createProviderWithoutCustomizations();
for (int effectId : KEYBOARD_FEEDBACK_CONSTANTS) {
- VibrationAttributes attrs = provider.getVibrationAttributesForHapticFeedback(
+ VibrationAttributes attrs = provider.getVibrationAttributes(
effectId, /* flags */ 0,
HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS);
assertWithMessage("Expected USAGE_IME_FEEDBACK for effect " + effectId)
diff --git a/services/tests/voiceinteractiontests/TEST_MAPPING b/services/tests/voiceinteractiontests/TEST_MAPPING
index 6cbc49a..466ba54 100644
--- a/services/tests/voiceinteractiontests/TEST_MAPPING
+++ b/services/tests/voiceinteractiontests/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "FrameworksVoiceInteractionTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksVoiceInteractionTests"
}
],
"postsubmit": [
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index 8f3adba..3d978e4 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -16,6 +16,8 @@
package com.android.server.policy;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.server.policy.PhoneWindowManager.DOUBLE_TAP_HOME_RECENT_SYSTEM_UI;
import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ALL_APPS;
import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ASSIST;
@@ -23,21 +25,21 @@
import static com.android.server.policy.PhoneWindowManager.SETTINGS_KEY_BEHAVIOR_NOTIFICATION_PANEL;
import android.hardware.input.KeyGestureEvent;
+import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.KeyEvent;
import androidx.test.filters.MediumTest;
import com.android.internal.annotations.Keep;
+import junit.framework.Assert;
+
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,10 +48,6 @@
@RunWith(JUnitParamsRunner.class)
public class KeyGestureEventTests extends ShortcutKeyTestBase {
- @Rule
- public final CheckFlagsRule mCheckFlagsRule =
- DeviceFlagsValueProvider.createCheckFlagsRule();
-
private static final int META_KEY = KeyEvent.KEYCODE_META_LEFT;
private static final int META_ON = MODIFIER.get(KeyEvent.KEYCODE_META_LEFT);
private static final int ALT_KEY = KeyEvent.KEYCODE_ALT_LEFT;
@@ -149,9 +147,9 @@
{"VOLUME_MUTE key -> Mute Volume", new int[]{KeyEvent.KEYCODE_VOLUME_MUTE},
KeyGestureEvent.KEY_GESTURE_TYPE_VOLUME_MUTE,
KeyEvent.KEYCODE_VOLUME_MUTE, 0},
- {"ALL_APPS key -> Open App Drawer in Accessibility mode",
+ {"ALL_APPS key -> Open App Drawer",
new int[]{KeyEvent.KEYCODE_ALL_APPS},
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
KeyEvent.KEYCODE_ALL_APPS, 0},
{"SEARCH key -> Launch Search Activity", new int[]{KeyEvent.KEYCODE_SEARCH},
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH,
@@ -160,8 +158,8 @@
new int[]{KeyEvent.KEYCODE_LANGUAGE_SWITCH},
KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
KeyEvent.KEYCODE_LANGUAGE_SWITCH, 0},
- {"META key -> Open App Drawer in Accessibility mode", new int[]{META_KEY},
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS, META_KEY,
+ {"META key -> Open App Drawer", new int[]{META_KEY},
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS, META_KEY,
META_ON},
{"Meta + Alt -> Toggle CapsLock", new int[]{META_KEY, ALT_KEY},
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK, ALT_KEY,
@@ -182,12 +180,12 @@
META_ON | CTRL_ON},
{"Meta + Ctrl + DPAD_LEFT -> Split screen navigation",
new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_LEFT},
- KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT,
KeyEvent.KEYCODE_DPAD_LEFT,
META_ON | CTRL_ON},
{"Meta + Ctrl + DPAD_RIGHT -> Split screen navigation",
new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_RIGHT},
- KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION,
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT,
KeyEvent.KEYCODE_DPAD_RIGHT,
META_ON | CTRL_ON},
{"Meta + L -> Lock Homescreen", new int[]{META_KEY, KeyEvent.KEYCODE_L},
@@ -320,18 +318,18 @@
new int[]{META_KEY, KeyEvent.KEYCODE_H}, LONG_PRESS_HOME_ASSIST,
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT, KeyEvent.KEYCODE_H,
META_ON},
- {"Long press HOME key -> Open App Drawer in Accessibility mode",
+ {"Long press HOME key -> Open App Drawer",
new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_ALL_APPS,
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
KeyEvent.KEYCODE_HOME, 0},
- {"Long press META + ENTER -> Open App Drawer in Accessibility mode",
+ {"Long press META + ENTER -> Open App Drawer",
new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, LONG_PRESS_HOME_ALL_APPS,
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
KeyEvent.KEYCODE_ENTER, META_ON},
- {"Long press META + H -> Open App Drawer in Accessibility mode",
+ {"Long press META + H -> Open App Drawer",
new int[]{META_KEY, KeyEvent.KEYCODE_H},
LONG_PRESS_HOME_ALL_APPS,
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
KeyEvent.KEYCODE_H, META_ON}};
}
@@ -428,7 +426,7 @@
}
@Test
- @RequiresFlagsEnabled(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT)
+ @EnableFlags(com.android.server.flags.Flags.FLAG_NEW_BUGREPORT_KEYBOARD_SHORTCUT)
public void testBugreportShortcutPress() {
testShortcutInternal("Meta + Ctrl + Del -> Trigger bug report",
new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DEL},
@@ -444,4 +442,161 @@
new int[]{expectedKey}, expectedModifierState, expectedKeyGestureType,
"Failed while executing " + testName);
}
+
+ @Test
+ public void testKeyGestureRecentApps() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS));
+ mPhoneWindowManager.assertShowRecentApps();
+ }
+
+ @Test
+ public void testKeyGestureAppSwitch() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH));
+ mPhoneWindowManager.assertToggleRecentApps();
+ }
+
+ @Test
+ public void testKeyGestureLaunchAssistant() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT));
+ mPhoneWindowManager.assertSearchManagerLaunchAssist();
+ }
+
+ @Test
+ public void testKeyGestureGoHome() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_HOME));
+ mPhoneWindowManager.assertGoToHomescreen();
+ }
+
+ @Test
+ public void testKeyGestureLaunchSystemSettings() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS));
+ mPhoneWindowManager.assertLaunchSystemSettings();
+ }
+
+ @Test
+ public void testKeyGestureLock() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN));
+ mPhoneWindowManager.assertLockedAfterAppTransitionFinished();
+ }
+
+ @Test
+ public void testKeyGestureToggleNotificationPanel() throws RemoteException {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL));
+ mPhoneWindowManager.assertTogglePanel();
+ }
+
+ @Test
+ public void testKeyGestureScreenshot() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT));
+ mPhoneWindowManager.assertTakeScreenshotCalled();
+ }
+
+ @Test
+ public void testKeyGestureTriggerBugReport() throws RemoteException {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_TRIGGER_BUG_REPORT));
+ mPhoneWindowManager.assertTakeBugreport(true);
+ }
+
+ @Test
+ public void testKeyGestureBack() {
+ Assert.assertTrue(sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BACK));
+ mPhoneWindowManager.assertBackEventInjected();
+ }
+
+ @Test
+ public void testKeyGestureMultiWindowNavigation() {
+ Assert.assertTrue(sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION));
+ mPhoneWindowManager.assertMoveFocusedTaskToFullscreen();
+ }
+
+ @Test
+ public void testKeyGestureDesktopMode() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE));
+ mPhoneWindowManager.assertMoveFocusedTaskToDesktop();
+ }
+
+ @Test
+ public void testKeyGestureSplitscreenNavigation() {
+ Assert.assertTrue(sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT));
+ mPhoneWindowManager.assertMoveFocusedTaskToStageSplit(true);
+
+ Assert.assertTrue(sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT));
+ mPhoneWindowManager.assertMoveFocusedTaskToStageSplit(false);
+ }
+
+ @Test
+ public void testKeyGestureSplitscreenFocus() {
+ Assert.assertTrue(sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT));
+ mPhoneWindowManager.assertSetSplitscreenFocus(true);
+
+ Assert.assertTrue(sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT));
+ mPhoneWindowManager.assertSetSplitscreenFocus(false);
+ }
+
+ @Test
+ public void testKeyGestureShortcutHelper() {
+ Assert.assertTrue(sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER));
+ mPhoneWindowManager.assertToggleShortcutsMenu();
+ }
+
+ @Test
+ public void testKeyGestureBrightnessChange() {
+ float[] currentBrightness = new float[]{0.1f, 0.05f, 0.0f};
+ float[] newBrightness = new float[]{0.065738f, 0.0275134f, 0.0f};
+
+ for (int i = 0; i < currentBrightness.length; i++) {
+ mPhoneWindowManager.prepareBrightnessDecrease(currentBrightness[i]);
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN));
+ mPhoneWindowManager.verifyNewBrightness(newBrightness[i]);
+ }
+ }
+
+ @Test
+ public void testKeyGestureRecentAppSwitcher() {
+ Assert.assertTrue(sendKeyGestureEventStart(
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER));
+ mPhoneWindowManager.assertShowRecentApps();
+
+ Assert.assertTrue(sendKeyGestureEventComplete(
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER));
+ mPhoneWindowManager.assertHideRecentApps();
+ }
+
+ @Test
+ public void testKeyGestureLanguageSwitch() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH));
+ mPhoneWindowManager.assertSwitchKeyboardLayout(1, DEFAULT_DISPLAY);
+
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ KeyEvent.META_SHIFT_ON));
+ mPhoneWindowManager.assertSwitchKeyboardLayout(-1, DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testKeyGestureLaunchSearch() {
+ Assert.assertTrue(
+ sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SEARCH));
+ mPhoneWindowManager.assertLaunchSearch();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/policy/MetaKeyEventsInterceptionTests.java b/services/tests/wmtests/src/com/android/server/policy/MetaKeyEventsInterceptionTests.java
deleted file mode 100644
index b979335..0000000
--- a/services/tests/wmtests/src/com/android/server/policy/MetaKeyEventsInterceptionTests.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2024 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.policy;
-
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.view.KeyEvent;
-import android.view.WindowManager;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.policy.KeyInterceptionInfo;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Testing {@link PhoneWindowManager} functionality of letting app intercepting key events
- * containing META.
- */
-@SmallTest
-public class MetaKeyEventsInterceptionTests extends ShortcutKeyTestBase {
-
- private static final List<KeyEvent> META_KEY_EVENTS = Arrays.asList(
- new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_LEFT),
- new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_RIGHT),
- new KeyEvent(/* downTime= */ 0, /* eventTime= */
- 0, /* action= */ 0, /* code= */ 0, /* repeat= */ 0,
- /* metaState= */ KeyEvent.META_META_ON));
-
- @Before
- public void setUp() {
- setUpPhoneWindowManager();
- }
-
- @Test
- public void doesntInterceptMetaKeyEvents_whenWindowAskedForIt() {
- mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ true);
- setWindowKeyInterceptionWithPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS);
-
- META_KEY_EVENTS.forEach(keyEvent -> {
- assertKeyInterceptionResult(keyEvent, /* intercepted= */ false);
- });
- }
-
- @Test
- public void interceptsMetaKeyEvents_whenWindowDoesntHaveFlagSet() {
- mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ true);
- setWindowKeyInterceptionWithPrivateFlags(0);
-
- META_KEY_EVENTS.forEach(keyEvent -> {
- assertKeyInterceptionResult(keyEvent, /* intercepted= */ true);
- });
- }
-
- @Test
- public void interceptsMetaKeyEvents_whenWindowDoesntHavePermission() {
- mPhoneWindowManager.overrideFocusedWindowButtonOverridePermission(/* granted= */ false);
- setWindowKeyInterceptionWithPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS);
-
- META_KEY_EVENTS.forEach(keyEvent -> {
- assertKeyInterceptionResult(keyEvent, /* intercepted= */ true);
- });
- }
-
- private void setWindowKeyInterceptionWithPrivateFlags(int privateFlags) {
- KeyInterceptionInfo info = new KeyInterceptionInfo(
- WindowManager.LayoutParams.TYPE_APPLICATION, privateFlags, "title", 0);
- mPhoneWindowManager.overrideWindowKeyInterceptionInfo(info);
- }
-
- private void assertKeyInterceptionResult(KeyEvent keyEvent, boolean intercepted) {
- long result = mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent);
- int expected = intercepted ? -1 : 0;
- assertThat(result).isEqualTo(expected);
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
index 536dcfb..af3dc1d 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java
@@ -46,6 +46,7 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
+import android.hardware.input.InputManager;
import android.os.PowerManager;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -95,6 +96,9 @@
mStatusBarManagerInternal = mock(StatusBarManagerInternal.class);
LocalServices.addService(StatusBarManagerInternal.class, mStatusBarManagerInternal);
mPhoneWindowManager.mKeyguardDelegate = mock(KeyguardServiceDelegate.class);
+ final InputManager im = mock(InputManager.class);
+ doNothing().when(im).registerKeyGestureEventHandler(any());
+ doReturn(im).when(mContext).getSystemService(eq(Context.INPUT_SERVICE));
}
@After
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 37e4fd6..50b7db4 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -56,6 +56,7 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.hardware.input.KeyGestureEvent;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.view.InputDevice;
@@ -228,6 +229,31 @@
sendKeyCombination(new int[]{keyCode}, 0 /*durationMillis*/, longPress, DEFAULT_DISPLAY);
}
+ boolean sendKeyGestureEventStart(int gestureType) {
+ return mPhoneWindowManager.sendKeyGestureEvent(
+ new KeyGestureEvent.Builder().setKeyGestureType(gestureType).setAction(
+ KeyGestureEvent.ACTION_GESTURE_START).build());
+ }
+
+ boolean sendKeyGestureEventComplete(int gestureType) {
+ return mPhoneWindowManager.sendKeyGestureEvent(
+ new KeyGestureEvent.Builder().setKeyGestureType(gestureType).setAction(
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE).build());
+ }
+
+ boolean sendKeyGestureEventComplete(int gestureType, int modifierState) {
+ return mPhoneWindowManager.sendKeyGestureEvent(
+ new KeyGestureEvent.Builder().setModifierState(modifierState).setKeyGestureType(
+ gestureType).setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE).build());
+ }
+
+ boolean sendKeyGestureEventComplete(int keycode, int modifierState, int gestureType) {
+ return mPhoneWindowManager.sendKeyGestureEvent(
+ new KeyGestureEvent.Builder().setKeycodes(new int[]{keycode}).setModifierState(
+ modifierState).setKeyGestureType(gestureType).setAction(
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE).build());
+ }
+
/**
* Since we use SettingsProviderRule to mock the ContentResolver in these
* tests, the settings observer registered by PhoneWindowManager will not
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 79c7ac1..98401b3 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -52,7 +52,6 @@
import static org.mockito.Mockito.description;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
import android.app.ActivityManagerInternal;
@@ -71,6 +70,7 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManager;
+import android.hardware.input.KeyGestureEvent;
import android.media.AudioManagerInternal;
import android.os.Handler;
import android.os.HandlerThread;
@@ -83,9 +83,11 @@
import android.os.Vibrator;
import android.os.VibratorInfo;
import android.os.test.TestLooper;
+import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.telecom.TelecomManager;
import android.view.Display;
+import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.autofill.AutofillManagerInternal;
@@ -118,6 +120,7 @@
import org.mockito.MockitoAnnotations;
import org.mockito.quality.Strictness;
+import java.util.List;
import java.util.function.Supplier;
class TestPhoneWindowManager {
@@ -298,6 +301,8 @@
doReturn(mAppOpsManager).when(mContext).getSystemService(eq(AppOpsManager.class));
doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class));
doReturn(mInputManager).when(mContext).getSystemService(eq(InputManager.class));
+ doNothing().when(mInputManager).registerKeyGestureEventHandler(any());
+ doNothing().when(mInputManager).unregisterKeyGestureEventHandler(any());
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mSensorPrivacyManager).when(mContext).getSystemService(
eq(SensorPrivacyManager.class));
@@ -417,6 +422,10 @@
mPhoneWindowManager.dispatchUnhandledKey(mInputToken, event, FLAG_INTERACTIVE);
}
+ boolean sendKeyGestureEvent(KeyGestureEvent event) {
+ return mPhoneWindowManager.handleKeyGestureEvent(event, mInputToken);
+ }
+
/**
* Provide access to the SettingsObserver so that tests can manually trigger Settings changes.
*/
@@ -584,6 +593,16 @@
doReturn(true).when(mInputManager).injectInputEvent(any(KeyEvent.class), anyInt());
}
+ void assertBackEventInjected() {
+ ArgumentCaptor<InputEvent> intentCaptor = ArgumentCaptor.forClass(InputEvent.class);
+ verify(mInputManager, times(2)).injectInputEvent(intentCaptor.capture(), anyInt());
+ List<InputEvent> inputEvents = intentCaptor.getAllValues();
+ Assert.assertEquals(KeyEvent.KEYCODE_BACK, ((KeyEvent) inputEvents.get(0)).getKeyCode());
+ Assert.assertEquals(KeyEvent.KEYCODE_BACK, ((KeyEvent) inputEvents.get(1)).getKeyCode());
+ // Reset verifier for next call.
+ Mockito.clearInvocations(mContext);
+ }
+
void overrideSearchKeyBehavior(int behavior) {
mPhoneWindowManager.mSearchKeyBehavior = behavior;
}
@@ -614,10 +633,6 @@
.when(mButtonOverridePermissionChecker).canAppOverrideSystemKey(any(), anyInt());
}
- void overrideWindowKeyInterceptionInfo(KeyInterceptionInfo info) {
- when(mWindowManagerInternal.getKeyInterceptionInfoFromToken(any())).thenReturn(info);
- }
-
void overrideKeyEventPolicyFlags(int flags) {
mKeyEventPolicyFlags = flags;
}
@@ -685,6 +700,24 @@
verify(mSearchManager).launchAssist(any());
}
+ void assertLaunchSystemSettings() {
+ mTestLooper.dispatchAll();
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).startActivityAsUser(intentCaptor.capture(), any(), any());
+ Assert.assertEquals(Settings.ACTION_SETTINGS, intentCaptor.getValue().getAction());
+ // Reset verifier for next call.
+ Mockito.clearInvocations(mContext);
+ }
+
+ void assertLaunchSearch() {
+ mTestLooper.dispatchAll();
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).startActivityAsUser(intentCaptor.capture(), any(), any());
+ Assert.assertEquals(Intent.ACTION_WEB_SEARCH, intentCaptor.getValue().getAction());
+ // Reset verifier for next call.
+ Mockito.clearInvocations(mContext);
+ }
+
void assertLaunchCategory(String category) {
mTestLooper.dispatchAll();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -725,6 +758,36 @@
verify(mStatusBarManagerInternal).showRecentApps(anyBoolean());
}
+ void assertHideRecentApps() {
+ mTestLooper.dispatchAll();
+ verify(mStatusBarManagerInternal).hideRecentApps(anyBoolean(), anyBoolean());
+ }
+
+ void assertToggleRecentApps() {
+ mTestLooper.dispatchAll();
+ verify(mStatusBarManagerInternal).toggleRecentApps();
+ }
+
+ void assertMoveFocusedTaskToDesktop() {
+ mTestLooper.dispatchAll();
+ verify(mStatusBarManagerInternal).moveFocusedTaskToDesktop(anyInt());
+ }
+
+ void assertMoveFocusedTaskToFullscreen() {
+ mTestLooper.dispatchAll();
+ verify(mStatusBarManagerInternal).moveFocusedTaskToFullscreen(anyInt());
+ }
+
+ void assertMoveFocusedTaskToStageSplit(boolean leftOrTop) {
+ mTestLooper.dispatchAll();
+ verify(mStatusBarManagerInternal).moveFocusedTaskToStageSplit(anyInt(), eq(leftOrTop));
+ }
+
+ void assertSetSplitscreenFocus(boolean leftOrTop) {
+ mTestLooper.dispatchAll();
+ verify(mStatusBarManagerInternal).setSplitscreenFocus(eq(leftOrTop));
+ }
+
void assertStatusBarStartAssist() {
mTestLooper.dispatchAll();
verify(mStatusBarManagerInternal).startAssist(any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index e2e76d6..577b02a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -39,6 +39,8 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.ApplicationInfo.CATEGORY_SOCIAL;
+import static android.content.pm.ApplicationInfo.CATEGORY_GAME;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
@@ -137,6 +139,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import android.provider.DeviceConfig;
import android.util.MutableBoolean;
import android.view.DisplayInfo;
@@ -2655,21 +2658,43 @@
@Test
public void testSetOrientation() {
+ assertSetOrientation(Build.VERSION_CODES.VANILLA_ICE_CREAM, CATEGORY_SOCIAL, true);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_UNIVERSAL_RESIZABLE_BY_DEFAULT)
+ public void testSetOrientation_restrictedByTargetSdk() {
+ assertSetOrientation(Build.VERSION_CODES.CUR_DEVELOPMENT, CATEGORY_SOCIAL, false);
+ assertSetOrientation(Build.VERSION_CODES.CUR_DEVELOPMENT, CATEGORY_GAME, true);
+
+ // Blanket application, also ignoring Target SDK
+ mWm.mConstants.mIgnoreActivityOrientationRequest = true;
+ assertSetOrientation(Build.VERSION_CODES.VANILLA_ICE_CREAM, CATEGORY_SOCIAL, false);
+ }
+
+ private void assertSetOrientation(int targetSdk, int category, boolean expectRotate) {
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ activity.mTargetSdk = targetSdk;
+ activity.info.applicationInfo.category = category;
+
activity.setVisible(true);
// Assert orientation is unspecified to start.
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation());
+ // Request orientation and see if it can be applied.
activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation());
+ if (expectRotate) {
+ assertEquals("targetSdk=" + targetSdk + " should be able to enter landscape",
+ SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation());
+ } else {
+ assertEquals("targetSdk=" + targetSdk + " should not be able to enter landscape",
+ SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation());
+ }
mDisplayContent.removeAppToken(activity.token);
// Assert orientation is unset to after container is removed.
assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
-
- // Reset display frozen state
- mWm.mDisplayFrozen = false;
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index eca4d21..85cb1bcc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -369,8 +369,10 @@
"startingWin");
startingWin.setHasSurface(true);
assertTrue(startingWin.canBeImeTarget());
+ final WindowContainer imeSurfaceParentWindow = mock(WindowContainer.class);
final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class);
- doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent();
+ doReturn(imeSurfaceParent).when(imeSurfaceParentWindow).getSurfaceControl();
+ doReturn(imeSurfaceParentWindow).when(mDisplayContent).computeImeParent();
spyOn(imeContainer);
mDisplayContent.setImeInputTarget(startingWin);
@@ -406,8 +408,11 @@
"startingWin");
startingWin.setHasSurface(true);
assertTrue(startingWin.canBeImeTarget());
+ final WindowContainer imeSurfaceParentWindow = mock(WindowContainer.class);
final SurfaceControl imeSurfaceParent = mock(SurfaceControl.class);
- doReturn(imeSurfaceParent).when(mDisplayContent).computeImeParent();
+ doReturn(imeSurfaceParent).when(imeSurfaceParentWindow).getSurfaceControl();
+ doReturn(imeSurfaceParentWindow).when(mDisplayContent).computeImeParent();
+
// Main precondition for this test: organize the ImeContainer.
final IDisplayAreaOrganizer mockImeOrganizer = mock(IDisplayAreaOrganizer.class);
@@ -639,10 +644,11 @@
ws.matchesDisplayAreaBounds());
assertTrue("IME shouldn't be attached to app",
- dc.computeImeParent() != dc.getImeTarget(IME_TARGET_LAYERING).getWindow()
- .mActivityRecord.getSurfaceControl());
+ dc.computeImeParent().getSurfaceControl() != dc.getImeTarget(
+ IME_TARGET_LAYERING).getWindow().mActivityRecord.getSurfaceControl());
assertEquals("IME should be attached to display",
- dc.getImeContainer().getParent().getSurfaceControl(), dc.computeImeParent());
+ dc.getImeContainer().getParent().getSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
private WindowState[] createNotDrawnWindowsOn(DisplayContent displayContent, int... types) {
@@ -1191,8 +1197,9 @@
final DisplayContent dc = createNewDisplay();
dc.setImeLayeringTarget(createWindow(null, TYPE_BASE_APPLICATION, "app"));
dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
- assertEquals(dc.getImeTarget(IME_TARGET_LAYERING).getWindow()
- .mActivityRecord.getSurfaceControl(), dc.computeImeParent());
+ assertEquals(dc.getImeTarget(
+ IME_TARGET_LAYERING).getWindow().mActivityRecord.getSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
@Test
@@ -1202,7 +1209,8 @@
dc.getImeTarget(IME_TARGET_LAYERING).getWindow().setWindowingMode(
WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
- assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
+ assertEquals(dc.getImeContainer().getParentSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
@SetupWindows(addWindows = W_ACTIVITY)
@@ -1213,7 +1221,7 @@
mDisplayContent.setImeLayeringTarget(mAppWindow);
// The surface parent of IME should be the display instead of app window.
assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(),
- mDisplayContent.computeImeParent());
+ mDisplayContent.computeImeParent().getSurfaceControl());
}
@Test
@@ -1221,7 +1229,8 @@
final DisplayContent dc = createNewDisplay();
dc.setImeLayeringTarget(createWindow(null, TYPE_STATUS_BAR, "statusBar"));
dc.setImeInputTarget(dc.getImeTarget(IME_TARGET_LAYERING).getWindow());
- assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
+ assertEquals(dc.getImeContainer().getParentSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
@SetupWindows(addWindows = W_ACTIVITY)
@@ -1232,7 +1241,8 @@
doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
mDisplayContent.setImeLayeringTarget(app1);
mDisplayContent.setImeInputTarget(app1);
- assertEquals(app1.mActivityRecord.getSurfaceControl(), mDisplayContent.computeImeParent());
+ assertEquals(app1.mActivityRecord.getSurfaceControl(),
+ mDisplayContent.computeImeParent().getSurfaceControl());
mDisplayContent.setImeLayeringTarget(app2);
// Expect null means no change IME parent when the IME layering target not yet
// request IME to be the input target.
@@ -1250,7 +1260,7 @@
mDisplayContent.setImeInputTarget(app);
assertFalse(mDisplayContent.shouldImeAttachedToApp());
assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(),
- mDisplayContent.computeImeParent());
+ mDisplayContent.computeImeParent().getSurfaceControl());
}
@Test
@@ -1275,7 +1285,8 @@
assertEquals(dc.getImeTarget(IME_TARGET_LAYERING), dc.getImeInputTarget());
// The ImeParent should be the display.
- assertEquals(dc.getImeContainer().getParent().getSurfaceControl(), dc.computeImeParent());
+ assertEquals(dc.getImeContainer().getParent().getSurfaceControl(),
+ dc.computeImeParent().getSurfaceControl());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 2f2b4732..b7aa730 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -45,6 +45,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+import com.android.server.wm.TestDisplayWindowSettingsProvider.TestStorage;
import org.junit.After;
import org.junit.Before;
@@ -516,81 +517,4 @@
}
return fullyDeleted;
}
-
- /** In-memory storage implementation. */
- public class TestStorage implements DisplayWindowSettingsProvider.WritableSettingsStorage {
- private InputStream mReadStream;
- private ByteArrayOutputStream mWriteStream;
-
- private boolean mWasSuccessful;
-
- /**
- * Returns input stream for reading. By default tries forward the output stream if previous
- * write was successful.
- * @see #closeRead()
- */
- @Override
- public InputStream openRead() throws FileNotFoundException {
- if (mReadStream == null && mWasSuccessful) {
- mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
- }
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.mark(Integer.MAX_VALUE);
- }
- return mReadStream;
- }
-
- /** Must be called after each {@link #openRead} to reset the position in the stream. */
- void closeRead() throws IOException {
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.reset();
- }
- mReadStream = null;
- }
-
- /**
- * Creates new or resets existing output stream for write. Automatically closes previous
- * read stream, since following reads should happen based on this new write.
- */
- @Override
- public OutputStream startWrite() throws IOException {
- if (mWriteStream == null) {
- mWriteStream = new ByteArrayOutputStream();
- } else {
- mWriteStream.reset();
- }
- if (mReadStream != null) {
- closeRead();
- }
- return mWriteStream;
- }
-
- @Override
- public void finishWrite(OutputStream os, boolean success) {
- mWasSuccessful = success;
- try {
- os.close();
- } catch (IOException e) {
- // This method can't throw IOException since the super implementation doesn't, so
- // we just wrap it in a RuntimeException so we end up crashing the test all the
- // same.
- throw new RuntimeException(e);
- }
- }
-
- /** Overrides the read stream of the injector. By default it uses current write stream. */
- private void setReadStream(InputStream is) {
- mReadStream = is;
- }
-
- private boolean wasWriteSuccessful() {
- return mWasSuccessful;
- }
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index f743401..7bce828 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1640,7 +1640,7 @@
.build();
setUpApp(display);
prepareUnresizable(mActivity, /* maxAspect */ 0f, SCREEN_ORIENTATION_PORTRAIT);
- mActivity.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
assertFalse(mActivity.inSizeCompatMode());
// Resize app to make original app bounds larger than parent bounds.
@@ -1667,7 +1667,7 @@
.build();
setUpApp(display);
prepareUnresizable(mActivity, /* maxAspect */ 0f, SCREEN_ORIENTATION_PORTRAIT);
- mActivity.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
assertFalse(mActivity.inSizeCompatMode());
// Resize app to make original app bounds smaller than parent bounds.
@@ -1692,7 +1692,7 @@
.build();
setUpApp(display);
prepareUnresizable(mActivity, /* maxAspect */ 0f, SCREEN_ORIENTATION_PORTRAIT);
- mActivity.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
assertFalse(mActivity.inSizeCompatMode());
final Rect originalAppBounds = mActivity.getBounds();
@@ -1705,6 +1705,38 @@
assertEquals(originalAppBounds, mActivity.getBounds());
}
+ /**
+ * Test that when desktop mode is enabled, a freeform unresizeable activity is not up-scaled
+ * when exiting freeform despite its larger parent bounds.
+ */
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ public void testCompatScaling_freeformUnresizeableApp_exitFreeform_notScaled() {
+ doReturn(true).when(() ->
+ DesktopModeHelper.canEnterDesktopMode(any()));
+ final int dw = 600;
+ final int dh = 800;
+ final DisplayContent display = new TestDisplayContent.Builder(mAtm, dw, dh)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM)
+ .build();
+ setUpApp(display);
+ prepareUnresizable(mActivity, /* maxAspect */ 0f, SCREEN_ORIENTATION_PORTRAIT);
+ mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
+ final Rect originalAppBounds = mActivity.getBounds();
+
+ assertFalse(mActivity.inSizeCompatMode());
+
+ // Resize app to make original app bounds smaller than parent bounds.
+ mTask.getWindowConfiguration().setAppBounds(
+ new Rect(0, 0, dw + 300, dh + 400));
+ // Change windowing mode from freeform to fullscreen
+ mTask.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ mActivity.onConfigurationChanged(mTask.getConfiguration());
+ // App should enter size compat mode but remain its original size.
+ assertTrue(mActivity.inSizeCompatMode());
+ assertEquals(originalAppBounds, mActivity.getBounds());
+ }
+
@Test
public void testGetLetterboxInnerBounds_noScalingApplied() {
// Set up a display in portrait and ignoring orientation request.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 71cfbfd..08622e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -133,6 +133,7 @@
private final ArrayList<DeviceConfig.OnPropertiesChangedListener> mDeviceConfigListeners =
new ArrayList<>();
+ private AppCompatConfiguration mAppCompat;
private Description mDescription;
private Context mContext;
private StaticMockitoSession mMockitoSession;
@@ -379,6 +380,11 @@
mock(ActivityManagerService.class, withSettings().stubOnly());
mAtmService = new TestActivityTaskManagerService(mContext, amService);
LocalServices.addService(ActivityTaskManagerInternal.class, mAtmService.getAtmInternal());
+
+ // AppCompatConfiguration
+ mAppCompat = new AppCompatConfiguration(
+ ActivityThread.currentActivityThread().getSystemUiContext());
+
// Create a fake WindowProcessController for the system process.
final WindowProcessController wpc =
addProcess("android", "system", 1485 /* pid */, 1000 /* uid */);
@@ -394,7 +400,7 @@
mWmService = WindowManagerService.main(
mContext, mImService, false, wmPolicy, mAtmService,
testDisplayWindowSettingsProvider, StubTransaction::new,
- MockSurfaceControlBuilder::new);
+ MockSurfaceControlBuilder::new, mAppCompat);
spyOn(mWmService);
spyOn(mWmService.mRoot);
// Invoked during {@link ActivityStack} creation.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index fd959b9..65a6a69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -884,7 +884,7 @@
// The ImeParent should be the display.
assertEquals(mDisplayContent.getImeContainer().getParent().getSurfaceControl(),
- mDisplayContent.computeImeParent());
+ mDisplayContent.computeImeParent().getSurfaceControl());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
index e11df98..877f65c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayWindowSettingsProvider.java
@@ -22,6 +22,16 @@
import java.util.HashMap;
import java.util.Map;
+import com.android.server.wm.DisplayWindowSettingsProvider.WritableSettingsStorage;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
/**
* In-memory DisplayWindowSettingsProvider used in tests. Ensures no settings are read from or
* written to device-specific display settings files.
@@ -30,6 +40,10 @@
private final Map<String, SettingsEntry> mOverrideSettingsMap = new HashMap<>();
+ public TestDisplayWindowSettingsProvider() {
+ super(new TestStorage(), new TestStorage());
+ }
+
@Override
@NonNull
public SettingsEntry getSettings(@NonNull DisplayInfo info) {
@@ -76,4 +90,81 @@
private static String getIdentifier(DisplayInfo displayInfo) {
return displayInfo.uniqueId;
}
+
+ /** In-memory storage implementation. */
+ public static class TestStorage implements WritableSettingsStorage {
+ private InputStream mReadStream;
+ private ByteArrayOutputStream mWriteStream;
+
+ private boolean mWasSuccessful;
+
+ /**
+ * Returns input stream for reading. By default tries forward the output stream if previous
+ * write was successful.
+ * @see #closeRead()
+ */
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ if (mReadStream == null && mWasSuccessful) {
+ mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
+ }
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.mark(Integer.MAX_VALUE);
+ }
+ return mReadStream;
+ }
+
+ /** Must be called after each {@link #openRead} to reset the position in the stream. */
+ public void closeRead() throws IOException {
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.reset();
+ }
+ mReadStream = null;
+ }
+
+ /**
+ * Creates new or resets existing output stream for write. Automatically closes previous
+ * read stream, since following reads should happen based on this new write.
+ */
+ @Override
+ public OutputStream startWrite() throws IOException {
+ if (mWriteStream == null) {
+ mWriteStream = new ByteArrayOutputStream();
+ } else {
+ mWriteStream.reset();
+ }
+ if (mReadStream != null) {
+ closeRead();
+ }
+ return mWriteStream;
+ }
+
+ @Override
+ public void finishWrite(OutputStream os, boolean success) {
+ mWasSuccessful = success;
+ try {
+ os.close();
+ } catch (IOException e) {
+ // This method can't throw IOException since the super implementation doesn't, so
+ // we just wrap it in a RuntimeException so we end up crashing the test all the
+ // same.
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Overrides the read stream of the injector. By default it uses current write stream. */
+ public void setReadStream(InputStream is) {
+ mReadStream = is;
+ }
+
+ public boolean wasWriteSuccessful() {
+ return mWasSuccessful;
+ }
+ }
}
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 5a54af1..2d5e5da 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -80,6 +80,7 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
@@ -88,9 +89,12 @@
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.IBinder;
import android.os.InputConfig;
import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.util.ArraySet;
@@ -116,6 +120,7 @@
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.testutils.StubTransaction;
import com.android.server.wm.SensitiveContentPackages.PackageInfo;
+import com.android.window.flags.Flags;
import org.junit.After;
import org.junit.Test;
@@ -965,6 +970,88 @@
assertTrue(testFlag(handle.inputConfig, InputConfig.NO_INPUT_CHANNEL));
}
+ @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesLetterboxBoundsIfTransformedBoundsAndLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Transformed bounds used for size of touchable region if letterbox inner bounds are empty.
+ final Rect transformedBounds = new Rect(0, 0, 300, 500);
+ doReturn(transformedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is disabled and letterboxInnerBounds is not empty,
+ // touchable region should match letterboxInnerBounds always.
+ assertEquals(letterboxInnerBounds, outRegion.getBounds());
+ }
+
+ @DisableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesLetterboxBoundsIfNullTransformedBoundsAndLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Fragment bounds used for size of touchable region if letterbox inner bounds are empty
+ // and Transform bounds are null.
+ doReturn(null).when(win.mToken).getFixedRotationTransformDisplayBounds();
+ final Rect fragmentBounds = new Rect(0, 0, 300, 500);
+ final TaskFragment taskFragment = win.mActivityRecord.getTaskFragment();
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(fragmentBounds);
+ return null;
+ }).when(taskFragment).getDimBounds(any());
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is disabled and letterboxInnerBounds is not empty,
+ // touchable region should match letterboxInnerBounds always.
+ assertEquals(letterboxInnerBounds, outRegion.getBounds());
+ }
+
+ @EnableFlags(Flags.FLAG_SCROLLING_FROM_LETTERBOX)
+ @Test
+ public void testTouchRegionUsesTransformedBoundsIfLetterboxScrolling() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+
+ // Transformed bounds used for size of touchable region if letterbox inner bounds are empty.
+ final Rect transformedBounds = new Rect(0, 0, 300, 500);
+ doReturn(transformedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
+
+ // Otherwise, touchable region should match letterbox inner bounds.
+ final Rect letterboxInnerBounds = new Rect(30, 0, 270, 500);
+ doAnswer(invocation -> {
+ Rect rect = invocation.getArgument(0);
+ rect.set(letterboxInnerBounds);
+ return null;
+ }).when(win.mActivityRecord).getLetterboxInnerBounds(any());
+
+ Region outRegion = new Region();
+ win.getSurfaceTouchableRegion(outRegion, win.mAttrs);
+
+ // Because scrollingFromLetterbox flag is enabled and transformedBounds are non-null,
+ // touchable region should match transformedBounds.
+ assertEquals(transformedBounds, outRegion.getBounds());
+ }
+
@Test
public void testHasActiveVisibleWindow() {
final int uid = ActivityBuilder.DEFAULT_FAKE_UID;
diff --git a/services/translation/java/com/android/server/translation/TEST_MAPPING b/services/translation/java/com/android/server/translation/TEST_MAPPING
index 4090b4a..0b97358 100644
--- a/services/translation/java/com/android/server/translation/TEST_MAPPING
+++ b/services/translation/java/com/android/server/translation/TEST_MAPPING
@@ -1,12 +1,7 @@
{
"presubmit": [
{
- "name": "CtsTranslationTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTranslationTestCases"
}
]
}
diff --git a/services/usage/java/com/android/server/usage/TEST_MAPPING b/services/usage/java/com/android/server/usage/TEST_MAPPING
index c878054..79b294c 100644
--- a/services/usage/java/com/android/server/usage/TEST_MAPPING
+++ b/services/usage/java/com/android/server/usage/TEST_MAPPING
@@ -7,33 +7,15 @@
"name": "FrameworksServicesTests_android_server_usage"
},
{
- "name": "CtsBRSTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "CtsBRSTestCases"
}
],
"postsubmit": [
{
- "name": "CtsUsageStatsTestCases",
- "options": [
- {
- "include-filter": "android.app.usage.cts.UsageStatsTest"
- }
- ]
+ "name": "CtsUsageStatsTestCases_cts_usagestatstest_ExcludeMediumAndLarge"
},
{
- "name": "CtsShortcutManagerTestCases",
- "options": [
- {
- "include-filter": "android.content.pm.cts.shortcutmanager.ShortcutManagerUsageTest"
- }
- ]
+ "name": "CtsShortcutManagerTestCases_shortcutmanager_shortcutmanagerusagetest"
}
]
}
diff --git a/services/voiceinteraction/TEST_MAPPING b/services/voiceinteraction/TEST_MAPPING
index e3d2549..3a68b33 100644
--- a/services/voiceinteraction/TEST_MAPPING
+++ b/services/voiceinteraction/TEST_MAPPING
@@ -12,44 +12,19 @@
]
},
{
- "name": "CtsAssistTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsAssistTestCases"
},
{
- "name": "CtsVoiceInteractionHostTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsVoiceInteractionHostTestCases"
},
{
- "name": "CtsLocalVoiceInteraction",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsLocalVoiceInteraction"
},
{
- "name": "FrameworksVoiceInteractionTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "FrameworksVoiceInteractionTests"
},
{
- "name": "CtsSoundTriggerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSoundTriggerTestCases"
}
]
}
diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING
index 775f1b8..4f6e558 100644
--- a/telecomm/TEST_MAPPING
+++ b/telecomm/TEST_MAPPING
@@ -1,70 +1,30 @@
{
"presubmit": [
{
- "name": "TeleServiceTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TeleServiceTests"
},
{
- "name": "TelecomUnitTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TelecomUnitTests"
},
{
- "name": "TelephonyProviderTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TelephonyProviderTests"
},
{
- "name": "CtsTelephony2TestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephony2TestCases"
},
{
- "name": "CtsTelephony3TestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephony3TestCases"
},
{
- "name": "CtsSimRestrictedApisTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSimRestrictedApisTestCases"
},
{
- "name": "CtsTelephonyProviderTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephonyProviderTestCases"
}
],
"presubmit-large": [
{
- "name": "CtsTelecomTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelecomTestCases"
}
]
}
diff --git a/telephony/TEST_MAPPING b/telephony/TEST_MAPPING
index 73e3dcd..4a4bae3 100644
--- a/telephony/TEST_MAPPING
+++ b/telephony/TEST_MAPPING
@@ -1,60 +1,25 @@
{
"presubmit": [
{
- "name": "TeleServiceTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TeleServiceTests"
},
{
- "name": "TelecomUnitTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TelecomUnitTests"
},
{
- "name": "TelephonyProviderTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TelephonyProviderTests"
},
{
- "name": "CtsTelephony2TestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephony2TestCases"
},
{
- "name": "CtsTelephony3TestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephony3TestCases"
},
{
- "name": "CtsSimRestrictedApisTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsSimRestrictedApisTestCases"
},
{
- "name": "CtsTelephonyProviderTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "CtsTelephonyProviderTestCases"
}
]
}
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index b80610a..4ccbc32 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -816,7 +816,8 @@
* @param callingUid pass Binder.callingUid().
*/
public static void enforceShellOnly(int callingUid, String message) {
- if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+ if (UserHandle.isSameApp(callingUid, Process.SHELL_UID)
+ || UserHandle.isSameApp(callingUid, Process.ROOT_UID)) {
return; // okay
}
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index f31a87f..4224338 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -60,6 +60,7 @@
public final class TelephonyUtils {
private static final String LOG_TAG = "TelephonyUtils";
+ public static final boolean FORCE_VERBOSE_STATE_LOGGING = false; /* stopship if true */
public static boolean IS_USER = "user".equals(android.os.Build.TYPE);
public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 51e0c33..6faef7e 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3785,7 +3785,7 @@
}
private boolean isSystemProcess() {
- return Process.myUid() == Process.SYSTEM_UID;
+ return UserHandle.isSameApp(Process.myUid(), Process.SYSTEM_UID);
}
/**
diff --git a/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt b/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt
index afb3593..4712d6b 100644
--- a/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt
+++ b/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt
@@ -4,6 +4,7 @@
import android.content.Context
import android.os.Bundle
import android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE
+import android.security.attestationverification.AttestationVerificationManager.PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS
import android.security.attestationverification.AttestationVerificationManager.PARAM_PUBLIC_KEY
import android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE
import android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS
@@ -162,6 +163,41 @@
}
@Test
+ fun verifyAttestation_returnsSuccessPatchDataWithinMaxPatchDiff() {
+ val verifier = AttestationVerificationPeerDeviceVerifier(
+ context, dumpLogger, trustAnchors, false, LocalDate.of(2023, 3, 1),
+ LocalDate.of(2023, 2, 1)
+ )
+ val challengeRequirements = Bundle()
+ challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray())
+ challengeRequirements.putInt(PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS, 24)
+
+ val result = verifier.verifyAttestation(
+ TYPE_CHALLENGE, challengeRequirements,
+ TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()
+ )
+ assertThat(result).isEqualTo(RESULT_SUCCESS)
+ }
+
+ @Test
+ fun verifyAttestation_returnsFailurePatchDataNotWithinMaxPatchDiff() {
+ val verifier = AttestationVerificationPeerDeviceVerifier(
+ context, dumpLogger, trustAnchors, false, LocalDate.of(2024, 10, 1),
+ LocalDate.of(2024, 9, 1)
+ )
+ val challengeRequirements = Bundle()
+ challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray())
+ challengeRequirements.putInt(PARAM_MAX_PATCH_LEVEL_DIFF_MONTHS, 24)
+
+ val result = verifier.verifyAttestation(
+ TYPE_CHALLENGE, challengeRequirements,
+ // The patch date of this file is early 2022
+ TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()
+ )
+ assertThat(result).isEqualTo(RESULT_FAILURE)
+ }
+
+ @Test
fun verifyAttestation_returnsFailureTrustedAnchorEmpty() {
val verifier = AttestationVerificationPeerDeviceVerifier(
context, dumpLogger, HashSet(), false, LocalDate.of(2022, 1, 1),
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
index 095c819..3753b23 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -23,7 +23,6 @@
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.flicker.legacy.LegacyFlickerTestFactory
import android.tools.flicker.subject.region.RegionSubject
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
@@ -43,7 +42,6 @@
*
* To run this test: `atest FlickerTestsActivityEmbedding:OpenTrampolineActivityTest`
*/
-@FlakyTest(bugId = 341209752)
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
index 92b6b93..82e53c8 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnUnlockScreenTest.kt
@@ -54,7 +54,7 @@
}
transitions {
device.sleep()
- wmHelper.StateSyncBuilder().withoutTopVisibleAppWindows().waitForAndVerify()
+ wmHelper.StateSyncBuilder().withKeyguardShowing().waitForAndVerify()
UnlockScreenRule.unlockScreen(device)
wmHelper.StateSyncBuilder().withImeShown().waitForAndVerify()
}
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
new file mode 100644
index 0000000..69fde01
--- /dev/null
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 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.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.helpers.SYSTEMUI_PACKAGE
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
+import android.util.Log
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.UiObjectNotFoundException
+import androidx.test.uiautomator.UiScrollable
+import androidx.test.uiautomator.UiSelector
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import java.util.regex.Pattern
+
+class StartMediaProjectionAppHelper
+@JvmOverloads
+constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.StartMediaProjectionActivity.LABEL,
+ component: ComponentNameMatcher =
+ ActivityOptions.StartMediaProjectionActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) {
+ private val packageManager = instr.context.packageManager
+
+ fun startEntireScreenMediaProjection(wmHelper: WindowManagerStateHelper) {
+ clickStartMediaProjectionButton()
+ chooseEntireScreenOption()
+ startScreenSharing()
+ wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+ }
+
+ fun startSingleAppMediaProjection(
+ wmHelper: WindowManagerStateHelper,
+ targetApp: StandardAppHelper
+ ) {
+ clickStartMediaProjectionButton()
+ chooseSingleAppOption()
+ startScreenSharing()
+ selectTargetApp(targetApp.appName)
+ wmHelper
+ .StateSyncBuilder()
+ .withAppTransitionIdle()
+ .withWindowSurfaceAppeared(targetApp)
+ .waitForAndVerify()
+ }
+
+ private fun clickStartMediaProjectionButton() {
+ findObject(By.res(packageName, START_MEDIA_PROJECTION_BUTTON_ID)).also { it.click() }
+ }
+
+ private fun chooseEntireScreenOption() {
+ findObject(By.res(SCREEN_SHARE_OPTIONS_PATTERN)).also { it.click() }
+
+ val entireScreenString = getSysUiResourceString(ENTIRE_SCREEN_STRING_RES_NAME)
+ findObject(By.text(entireScreenString)).also { it.click() }
+ }
+
+ private fun selectTargetApp(targetAppName: String) {
+ // Scroll to to find target app to launch then click app icon it to start capture
+ val scrollable = UiScrollable(UiSelector().scrollable(true))
+ try {
+ scrollable.scrollForward()
+ if (!scrollable.scrollIntoView(UiSelector().text(targetAppName))) {
+ Log.e(TAG, "Didn't find target app when scrolling")
+ return
+ }
+ } catch (e: UiObjectNotFoundException) {
+ Log.d(TAG, "There was no scrolling (UI may not be scrollable")
+ }
+
+ findObject(By.text(targetAppName)).also { it.click() }
+ }
+
+ private fun chooseSingleAppOption() {
+ findObject(By.res(SCREEN_SHARE_OPTIONS_PATTERN)).also { it.click() }
+
+ val singleAppString = getSysUiResourceString(SINGLE_APP_STRING_RES_NAME)
+ findObject(By.text(singleAppString)).also { it.click() }
+ }
+
+ private fun startScreenSharing() {
+ findObject(By.res(ACCEPT_RESOURCE_ID)).also { it.click() }
+ }
+
+ private fun findObject(selector: BySelector): UiObject2 =
+ uiDevice.wait(Until.findObject(selector), TIMEOUT) ?: error("Can't find object $selector")
+
+ private fun getSysUiResourceString(resName: String): String =
+ with(packageManager.getResourcesForApplication(SYSTEMUI_PACKAGE)) {
+ getString(getIdentifier(resName, "string", SYSTEMUI_PACKAGE))
+ }
+
+ companion object {
+ const val TAG: String = "StartMediaProjectionAppHelper"
+ const val TIMEOUT: Long = 5000L
+ const val ACCEPT_RESOURCE_ID: String = "android:id/button1"
+ const val START_MEDIA_PROJECTION_BUTTON_ID: String = "button_start_mp"
+ val SCREEN_SHARE_OPTIONS_PATTERN: Pattern =
+ Pattern.compile("$SYSTEMUI_PACKAGE:id/screen_share_mode_(options|spinner)")
+ const val ENTIRE_SCREEN_STRING_RES_NAME: String =
+ "screen_share_permission_dialog_option_entire_screen"
+ const val SINGLE_APP_STRING_RES_NAME: String =
+ "screen_share_permission_dialog_option_single_app"
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index e3b23b9..c55df86 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -19,6 +19,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_windowing_tools",
}
android_test {
@@ -46,6 +47,7 @@
"wm-flicker-common-app-helpers",
"wm-flicker-common-assertions",
"wm-flicker-window-extensions",
+ "wm-shell-flicker-utils",
],
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 45260bd..f891606 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -21,6 +21,15 @@
android:targetSdkVersion="35"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/>
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<application android:allowBackup="false"
android:supportsRtl="true">
@@ -106,6 +115,17 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".StartMediaProjectionActivity"
+ android:theme="@style/CutoutNever"
+ android:resizeableActivity="false"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.StartMediaProjectionActivity"
+ android:label="StartMediaProjectionActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
<activity android:name=".PortraitImmersiveActivity"
android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitImmersiveActivity"
android:immersive="true"
@@ -404,6 +424,11 @@
android:name="android.voice_interaction"
android:resource="@xml/interaction_service"/>
</service>
+ <service android:name="com.android.wm.shell.flicker.utils.MediaProjectionService"
+ android:foregroundServiceType="mediaProjection"
+ android:label="WMShellTestsMediaProjectionService"
+ android:enabled="true">
+ </service>
</application>
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
new file mode 100644
index 0000000..46f01e6
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="@android:color/holo_orange_light">
+
+ <Button
+ android:id="@+id/button_start_mp"
+ android:layout_width="500dp"
+ android:layout_height="500dp"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="Start Media Projection"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 80c1dd0..e4de2c5 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -85,6 +85,12 @@
FLICKER_APP_PACKAGE + ".NonResizeablePortraitActivity");
}
+ public static class StartMediaProjectionActivity {
+ public static final String LABEL = "StartMediaProjectionActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".StartMediaProjectionActivity");
+ }
+
public static class PortraitImmersiveActivity {
public static final String LABEL = "PortraitImmersiveActivity";
public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
new file mode 100644
index 0000000..a24a482
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2021 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.wm.flicker.testapp;
+
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.EXTRA_MESSENGER;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.MSG_SERVICE_DESTROYED;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.MSG_START_FOREGROUND_DONE;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.hardware.display.VirtualDisplay;
+import android.media.ImageReader;
+import android.media.projection.MediaProjection;
+import android.media.projection.MediaProjectionManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Messenger;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.widget.Button;
+
+import com.android.wm.shell.flicker.utils.MediaProjectionService;
+
+public class StartMediaProjectionActivity extends Activity {
+
+ private static final String TAG = "StartMediaProjectionActivity";
+ private MediaProjectionManager mService;
+ private ImageReader mImageReader;
+ private VirtualDisplay mVirtualDisplay;
+ private MediaProjection mMediaProjection;
+ private MediaProjection.Callback mMediaProjectionCallback = new MediaProjection.Callback() {
+ @Override
+ public void onStop() {
+ super.onStop();
+ }
+
+ @Override
+ public void onCapturedContentResize(int width, int height) {
+ super.onCapturedContentResize(width, height);
+ }
+
+ @Override
+ public void onCapturedContentVisibilityChanged(boolean isVisible) {
+ super.onCapturedContentVisibilityChanged(isVisible);
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mService = getSystemService(MediaProjectionManager.class);
+ setContentView(R.layout.activity_start_media_projection);
+
+ Button startMediaProjectionButton = findViewById(R.id.button_start_mp);
+ startMediaProjectionButton.setOnClickListener(v ->
+ startActivityForResult(mService.createScreenCaptureIntent(), REQUEST_CODE));
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode != REQUEST_CODE) {
+ throw new IllegalStateException("Unknown request code: " + requestCode);
+ }
+ if (resultCode != RESULT_OK) {
+ throw new IllegalStateException("User denied screen sharing permission");
+ }
+ Log.d(TAG, "onActivityResult");
+ startMediaProjectionService(resultCode, data);
+ }
+
+ private void startMediaProjectionService(int resultCode, Intent resultData) {
+ final Messenger messenger = new Messenger(new Handler(Looper.getMainLooper(),
+ msg -> {
+ switch (msg.what) {
+ case MSG_START_FOREGROUND_DONE:
+ setupMediaProjection(resultCode, resultData);
+ return true;
+ case MSG_SERVICE_DESTROYED:
+ return true;
+ }
+ Log.e(TAG, "Unknown message from the FlickerMPService: " + msg.what);
+ return false;
+ }
+ ));
+
+ final Intent intent = new Intent()
+ .setComponent(new ComponentName(this, MediaProjectionService.class))
+ .putExtra(EXTRA_MESSENGER, messenger);
+ startForegroundService(intent);
+ }
+
+ private void setupMediaProjection(int resultCode, Intent resultData) {
+ mMediaProjection = mService.getMediaProjection(resultCode, resultData);
+ if (mMediaProjection == null) {
+ throw new IllegalStateException("cannot create new MediaProjection");
+ }
+
+ mMediaProjection.registerCallback(
+ mMediaProjectionCallback, new Handler(Looper.getMainLooper()));
+
+ Rect displayBounds = getWindowManager().getMaximumWindowMetrics().getBounds();
+ mImageReader = ImageReader.newInstance(
+ displayBounds.width(), displayBounds.height(), PixelFormat.RGBA_8888, 1);
+
+ mVirtualDisplay = mMediaProjection.createVirtualDisplay(
+ "DanielDisplay",
+ displayBounds.width(),
+ displayBounds.height(),
+ DisplayMetrics.DENSITY_HIGH,
+ /* flags= */ 0,
+ mImageReader.getSurface(),
+ new VirtualDisplay.Callback() {
+ @Override
+ public void onStopped() {
+ if (mMediaProjection != null) {
+ if (mMediaProjectionCallback != null) {
+ mMediaProjection.unregisterCallback(mMediaProjectionCallback);
+ mMediaProjectionCallback = null;
+ }
+ mMediaProjection.stop();
+ mMediaProjection = null;
+ }
+ if (mImageReader != null) {
+ mImageReader = null;
+ }
+ if (mVirtualDisplay != null) {
+ mVirtualDisplay.getSurface().release();
+ mVirtualDisplay.release();
+ mVirtualDisplay = null;
+ }
+ }
+ },
+ new Handler(Looper.getMainLooper())
+ );
+ }
+
+}
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index f3e040a..6742cbe 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -39,6 +39,7 @@
"flag-junit",
"frameworks-base-testutils",
"hamcrest-library",
+ "junit-params",
"kotlin-test",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
index a05d08c..914adc4 100644
--- a/tests/Input/AndroidManifest.xml
+++ b/tests/Input/AndroidManifest.xml
@@ -32,6 +32,14 @@
android:process=":externalProcess">
</activity>
+ <activity android:name="com.android.test.input.CaptureEventActivity"
+ android:label="Capture events"
+ android:configChanges="touchscreen|uiMode|orientation|screenSize|screenLayout|keyboardHidden|uiMode|navigation|keyboard|density|fontScale|layoutDirection|locale|mcc|mnc|smallestScreenSize"
+ android:enableOnBackInvokedCallback="false"
+ android:turnScreenOn="true"
+ android:exported="true">
+ </activity>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.test.input"
diff --git a/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu b/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu
new file mode 100644
index 0000000..1a9112b
--- /dev/null
+++ b/tests/Input/res/raw/google_pixel_tablet_touchscreen.evemu
@@ -0,0 +1,150 @@
+# EVEMU 1.2
+# One finger swipe gesture on the Google Pixel Tablet touchscreen
+N: NVTCapacitiveTouchScreen
+I: 001c 0603 7806 0100
+P: 02 00 00 00 00 00 00 00
+B: 00 0b 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 80 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 04 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 02 00 00 00 00 00 00 00 00
+B: 03 00 00 00 00 00 80 f3 46
+B: 04 00 00 00 00 00 00 00 00
+B: 05 00 00 00 00 00 00 00 00
+B: 11 00 00 00 00 00 00 00 00
+B: 12 00 00 00 00 00 00 00 00
+A: 2f 0 9 0 0 0
+A: 30 0 2559 0 0 11
+A: 31 0 1599 0 0 11
+A: 34 -4096 4096 0 0 0
+A: 35 0 1599 0 0 11
+A: 36 0 2559 0 0 11
+A: 37 0 2 0 0 0
+A: 39 0 65535 0 0 0
+A: 3a 0 256 0 0 0
+A: 3e 0 8 0 0 0
+E: 0.000001 0001 014a 0001
+E: 0.000001 0003 0039 0003
+E: 0.000001 0003 0035 0810
+E: 0.000001 0003 0036 1650
+E: 0.000001 0003 0030 0082
+E: 0.000001 0003 0031 0077
+E: 0.000001 0003 003a 0215
+E: 0.000001 0003 0034 3218
+E: 0.000001 0000 0000 0000
+E: 0.008818 0003 0035 0825
+E: 0.008818 0003 0036 1645
+E: 0.008818 0003 0034 3217
+E: 0.008818 0000 0000 0000
+E: 0.016306 0003 0035 0841
+E: 0.016306 0003 0036 1639
+E: 0.016306 0003 0034 3102
+E: 0.016306 0000 0000 0000
+E: 0.025653 0003 0035 0862
+E: 0.025653 0003 0036 1630
+E: 0.025653 0003 0034 3092
+E: 0.025653 0000 0000 0000
+E: 0.032936 0003 0035 0883
+E: 0.032936 0003 0036 1619
+E: 0.032936 0003 0034 3030
+E: 0.032936 0000 0000 0000
+E: 0.042072 0003 0035 0905
+E: 0.042072 0003 0036 1604
+E: 0.042072 0003 0034 2848
+E: 0.042072 0000 0000 0000
+E: 0.049569 0003 0035 0924
+E: 0.049569 0003 0036 1591
+E: 0.049569 0003 0034 2830
+E: 0.049569 0000 0000 0000
+E: 0.058706 0003 0035 0942
+E: 0.058706 0003 0036 1573
+E: 0.058706 0000 0000 0000
+E: 0.066207 0003 0035 0954
+E: 0.066207 0003 0036 1557
+E: 0.066207 0003 0034 2790
+E: 0.066207 0000 0000 0000
+E: 0.075337 0003 0035 0966
+E: 0.075337 0003 0036 1535
+E: 0.075337 0000 0000 0000
+E: 0.082841 0003 0035 0973
+E: 0.082841 0003 0036 1511
+E: 0.082841 0003 0034 2788
+E: 0.082841 0000 0000 0000
+E: 0.091972 0003 0035 0971
+E: 0.091972 0003 0036 1480
+E: 0.091972 0003 0034 2770
+E: 0.091972 0000 0000 0000
+E: 0.099474 0003 0035 0961
+E: 0.099474 0003 0036 1445
+E: 0.099474 0003 0034 2644
+E: 0.099474 0000 0000 0000
+E: 0.108631 0003 0035 0937
+E: 0.108631 0003 0036 1400
+E: 0.108631 0003 0030 0083
+E: 0.108631 0003 0034 2461
+E: 0.108631 0000 0000 0000
+E: 0.116109 0003 0035 0909
+E: 0.116109 0003 0036 1361
+E: 0.116109 0003 0034 2278
+E: 0.116109 0000 0000 0000
+E: 0.125263 0003 0035 0865
+E: 0.125263 0003 0036 1311
+E: 0.125263 0003 0034 2096
+E: 0.125263 0000 0000 0000
+E: 0.132741 0003 0035 0820
+E: 0.132741 0003 0036 1261
+E: 0.132741 0003 0034 2083
+E: 0.132741 0000 0000 0000
+E: 0.141876 0003 0035 0755
+E: 0.141876 0003 0036 1193
+E: 0.141876 0003 003a 0216
+E: 0.141876 0003 0034 2266
+E: 0.141876 0000 0000 0000
+E: 0.149376 0003 0035 0691
+E: 0.149376 0003 0036 1124
+E: 0.149376 0003 0034 2448
+E: 0.149376 0000 0000 0000
+E: 0.158510 0003 0035 0609
+E: 0.158510 0003 0036 1033
+E: 0.158510 0003 0034 2631
+E: 0.158510 0000 0000 0000
+E: 0.166011 0003 0035 0543
+E: 0.166011 0003 0036 0957
+E: 0.166011 0003 0034 2813
+E: 0.166011 0000 0000 0000
+E: 0.175182 0003 0035 0471
+E: 0.175182 0003 0036 0864
+E: 0.175182 0003 0031 0076
+E: 0.175182 0003 0034 2996
+E: 0.175182 0000 0000 0000
+E: 0.182683 0003 0035 0417
+E: 0.182683 0003 0036 0792
+E: 0.182683 0003 003a 0214
+E: 0.182683 0003 0034 3178
+E: 0.182683 0000 0000 0000
+E: 0.191777 0003 0035 0361
+E: 0.191777 0003 0036 0719
+E: 0.191777 0003 0031 0075
+E: 0.191777 0003 003a 0213
+E: 0.191777 0003 0034 2996
+E: 0.191777 0000 0000 0000
+E: 0.199431 0003 0035 0271
+E: 0.199431 0003 0036 0603
+E: 0.199431 0003 0030 0060
+E: 0.199431 0003 0031 0029
+E: 0.199431 0003 003a 0060
+E: 0.199431 0003 0034 2813
+E: 0.199431 0000 0000 0000
+E: 0.207943 0003 003a 0000
+E: 0.207943 0003 0039 -001
+E: 0.207943 0001 014a 0000
+E: 0.207943 0000 0000 0000
diff --git a/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json b/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json
new file mode 100644
index 0000000..df4f9fb
--- /dev/null
+++ b/tests/Input/res/raw/google_pixel_tablet_touchscreen_events.json
@@ -0,0 +1,34 @@
+[
+ {
+ "name": "One finger swipe",
+ "source": "TOUCHSCREEN",
+ "events": [
+ {"action":"DOWN","axes":{"AXIS_X":810,"AXIS_Y":1650,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.234087586402893},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":825,"AXIS_Y":1645,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.2337040901184082},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":841,"AXIS_Y":1639,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1896021366119385},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":862,"AXIS_Y":1630,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1857671737670898},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":883,"AXIS_Y":1619,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.1619905233383179},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":905,"AXIS_Y":1604,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0921943187713623},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":924,"AXIS_Y":1591,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0852913856506348},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":942,"AXIS_Y":1573,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0852913856506348},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":954,"AXIS_Y":1557,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0699516534805298},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":966,"AXIS_Y":1535,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0699516534805298},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":973,"AXIS_Y":1511,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.06918466091156},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":971,"AXIS_Y":1480,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0622817277908325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":961,"AXIS_Y":1445,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":82,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":82,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0139613151550293},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":937,"AXIS_Y":1400,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.9437817335128784},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":909,"AXIS_Y":1361,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.8736020922660828},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":865,"AXIS_Y":1311,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.803805947303772},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":820,"AXIS_Y":1261,"AXIS_PRESSURE":0.83984375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.7988204956054688},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":755,"AXIS_Y":1193,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.8690001368522644},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":691,"AXIS_Y":1124,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":0.9387962818145752},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":609,"AXIS_Y":1033,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.008975863456726},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":543,"AXIS_Y":957,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03126221150159836,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":77,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":77,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":471,"AXIS_Y":864,"AXIS_PRESSURE":0.84375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":76,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":76,"AXIS_ORIENTATION":1.1489516496658325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":417,"AXIS_Y":792,"AXIS_PRESSURE":0.8359375,"AXIS_SIZE":0.03106682375073433,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":76,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":76,"AXIS_ORIENTATION":1.2187477350234985},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":361,"AXIS_Y":719,"AXIS_PRESSURE":0.83203125,"AXIS_SIZE":0.03087143413722515,"AXIS_TOUCH_MAJOR":83,"AXIS_TOUCH_MINOR":75,"AXIS_TOOL_MAJOR":83,"AXIS_TOOL_MINOR":75,"AXIS_ORIENTATION":1.1489516496658325},"buttonState":[]},
+ {"action":"MOVE","axes":{"AXIS_X":271,"AXIS_Y":603,"AXIS_PRESSURE":0.234375,"AXIS_SIZE":0.017389604821801186,"AXIS_TOUCH_MAJOR":60,"AXIS_TOUCH_MINOR":29,"AXIS_TOOL_MAJOR":60,"AXIS_TOOL_MINOR":29,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]},
+ {"action":"UP","axes":{"AXIS_X":271,"AXIS_Y":603,"AXIS_PRESSURE":0.234375,"AXIS_SIZE":0.017389604821801186,"AXIS_TOUCH_MAJOR":60,"AXIS_TOUCH_MINOR":29,"AXIS_TOOL_MAJOR":60,"AXIS_TOOL_MINOR":29,"AXIS_ORIENTATION":1.0787720680236816},"buttonState":[]}
+ ]
+ }
+]
diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index 8829f74..c2e71f8 100644
--- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -17,8 +17,10 @@
package com.android.server.input
+import android.Manifest
import android.content.Context
import android.content.ContextWrapper
+import android.content.PermissionChecker
import android.hardware.display.DisplayManager
import android.hardware.display.DisplayViewport
import android.hardware.display.VirtualDisplay
@@ -28,19 +30,26 @@
import android.os.SystemClock
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
-import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.provider.Settings
import android.view.View.OnKeyListener
import android.view.InputDevice
import android.view.KeyEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
+import android.view.WindowManager
import android.test.mock.MockContentResolver
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.internal.util.test.FakeSettingsProvider
-import com.google.common.truth.Truth.assertThat
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.internal.policy.KeyInterceptionInfo
+import com.android.internal.util.test.FakeSettingsProvider
+import com.android.modules.utils.testing.ExtendedMockitoRule
+import com.android.server.LocalServices
+import com.android.server.wm.WindowManagerInternal
+import com.google.common.truth.Truth.assertThat
import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
@@ -49,15 +58,15 @@
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when`
import org.mockito.stubbing.OngoingStubbing
/**
@@ -69,15 +78,25 @@
@Presubmit
class InputManagerServiceTests {
- @get:Rule
- val mockitoRule = MockitoJUnit.rule()!!
+ companion object {
+ val ACTION_KEY_EVENTS = listOf(
+ KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_LEFT),
+ KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_META_RIGHT),
+ KeyEvent( /* downTime= */0, /* eventTime= */0, /* action= */0, /* code= */0,
+ /* repeat= */0, KeyEvent.META_META_ON
+ )
+ )
+ }
+
+ @JvmField
+ @Rule
+ val extendedMockitoRule =
+ ExtendedMockitoRule.Builder(this).mockStatic(LocalServices::class.java)
+ .mockStatic(PermissionChecker::class.java).build()!!
@get:Rule
val fakeSettingsProviderRule = FakeSettingsProvider.rule()!!
- @get:Rule
- val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()!!
-
@Mock
private lateinit var native: NativeInputManagerService
@@ -85,6 +104,9 @@
private lateinit var wmCallbacks: InputManagerService.WindowManagerCallbacks
@Mock
+ private lateinit var windowManagerInternal: WindowManagerInternal
+
+ @Mock
private lateinit var uEventManager: UEventManager
private lateinit var service: InputManagerService
@@ -119,6 +141,10 @@
whenever(context.getSystemService(InputManager::class.java)).thenReturn(inputManager)
whenever(context.getSystemService(Context.INPUT_SERVICE)).thenReturn(inputManager)
+ ExtendedMockito.doReturn(windowManagerInternal).`when` {
+ LocalServices.getService(eq(WindowManagerInternal::class.java))
+ }
+
assertTrue("Local service must be registered", this::localService.isInitialized)
service.setWindowManagerCallbacks(wmCallbacks)
}
@@ -195,7 +221,7 @@
}
@Test
- fun testAddAndRemoveVirtualmKeyboardLayoutAssociation() {
+ fun testAddAndRemoveVirtualKeyboardLayoutAssociation() {
val inputPort = "input port"
val languageTag = "language"
val layoutType = "layoutType"
@@ -206,6 +232,48 @@
verify(native, times(2)).changeKeyboardLayoutAssociation()
}
+ @Test
+ fun testActionKeyEventsForwardedToFocusedWindow_whenCorrectlyRequested() {
+ service.systemRunning()
+ overrideSendActionKeyEventsToFocusedWindow(
+ /* hasPermission = */true,
+ /* hasPrivateFlag = */true
+ )
+ whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(-1)
+
+ for (event in ACTION_KEY_EVENTS) {
+ assertEquals(0, service.interceptKeyBeforeDispatching(null, event, 0))
+ }
+ }
+
+ @Test
+ fun testActionKeyEventsNotForwardedToFocusedWindow_whenNoPermissions() {
+ service.systemRunning()
+ overrideSendActionKeyEventsToFocusedWindow(
+ /* hasPermission = */false,
+ /* hasPrivateFlag = */true
+ )
+ whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(-1)
+
+ for (event in ACTION_KEY_EVENTS) {
+ assertNotEquals(0, service.interceptKeyBeforeDispatching(null, event, 0))
+ }
+ }
+
+ @Test
+ fun testActionKeyEventsNotForwardedToFocusedWindow_whenNoPrivateFlag() {
+ service.systemRunning()
+ overrideSendActionKeyEventsToFocusedWindow(
+ /* hasPermission = */true,
+ /* hasPrivateFlag = */false
+ )
+ whenever(wmCallbacks.interceptKeyBeforeDispatching(any(), any(), anyInt())).thenReturn(-1)
+
+ for (event in ACTION_KEY_EVENTS) {
+ assertNotEquals(0, service.interceptKeyBeforeDispatching(null, event, 0))
+ }
+ }
+
private fun createVirtualDisplays(count: Int): List<VirtualDisplay> {
val displayManager: DisplayManager = context.getSystemService(
DisplayManager::class.java
@@ -373,6 +441,41 @@
verify(mockOnKeyListener).onKey(mockSurfaceView2, KeyEvent.KEYCODE_A, upEvent)
verify(mockOnKeyListener, never()).onKey(mockSurfaceView1, KeyEvent.KEYCODE_A, upEvent)
}
+
+ fun overrideSendActionKeyEventsToFocusedWindow(
+ hasPermission: Boolean,
+ hasPrivateFlag: Boolean
+ ) {
+ ExtendedMockito.doReturn(
+ if (hasPermission) {
+ PermissionChecker.PERMISSION_GRANTED
+ } else {
+ PermissionChecker.PERMISSION_HARD_DENIED
+ }
+ ).`when` {
+ PermissionChecker.checkPermissionForDataDelivery(
+ any(),
+ eq(Manifest.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW),
+ anyInt(),
+ anyInt(),
+ any(),
+ any(),
+ any()
+ )
+ }
+
+ val info = KeyInterceptionInfo(
+ /* type = */0,
+ if (hasPrivateFlag) {
+ WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS
+ } else {
+ 0
+ },
+ "title",
+ /* uid = */0
+ )
+ whenever(windowManagerInternal.getKeyInterceptionInfoFromToken(any())).thenReturn(info)
+ }
}
private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index e126797..ba36007 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -25,19 +25,27 @@
import android.hardware.input.InputManager
import android.hardware.input.InputManagerGlobal
import android.hardware.input.KeyGestureEvent
+import android.hardware.input.KeyGestureEvent.KeyGestureType
import android.os.IBinder
import android.os.Process
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
import android.view.InputDevice
+import android.view.KeyCharacterMap
import android.view.KeyEvent
import androidx.test.core.app.ApplicationProvider
+import com.android.internal.annotations.Keep
import com.android.internal.util.FrameworkStatsLog
import com.android.modules.utils.testing.ExtendedMockitoRule
+import junitparams.JUnitParamsRunner
+import junitparams.Parameters
+import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
@@ -48,6 +56,7 @@
* atest InputTests:KeyGestureControllerTests
*/
@Presubmit
+@RunWith(JUnitParamsRunner::class)
class KeyGestureControllerTests {
companion object {
@@ -59,6 +68,16 @@
.setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
.setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
.build()
+ val MODIFIER = mapOf(
+ KeyEvent.KEYCODE_CTRL_LEFT to (KeyEvent.META_CTRL_LEFT_ON or KeyEvent.META_CTRL_ON),
+ KeyEvent.KEYCODE_CTRL_RIGHT to (KeyEvent.META_CTRL_RIGHT_ON or KeyEvent.META_CTRL_ON),
+ KeyEvent.KEYCODE_ALT_LEFT to (KeyEvent.META_ALT_LEFT_ON or KeyEvent.META_ALT_ON),
+ KeyEvent.KEYCODE_ALT_RIGHT to (KeyEvent.META_ALT_RIGHT_ON or KeyEvent.META_ALT_ON),
+ KeyEvent.KEYCODE_SHIFT_LEFT to (KeyEvent.META_SHIFT_LEFT_ON or KeyEvent.META_SHIFT_ON),
+ KeyEvent.KEYCODE_SHIFT_RIGHT to (KeyEvent.META_SHIFT_RIGHT_ON or KeyEvent.META_SHIFT_ON),
+ KeyEvent.KEYCODE_META_LEFT to (KeyEvent.META_META_LEFT_ON or KeyEvent.META_META_ON),
+ KeyEvent.KEYCODE_META_RIGHT to (KeyEvent.META_META_RIGHT_ON or KeyEvent.META_META_ON),
+ )
}
@JvmField
@@ -75,6 +94,7 @@
private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
private lateinit var testLooper: TestLooper
private var events = mutableListOf<KeyGestureEvent>()
+ private var handleEvents = mutableListOf<KeyGestureEvent>()
@Before
fun setup() {
@@ -184,6 +204,452 @@
)
}
+ class TestData(
+ val name: String,
+ val keys: IntArray,
+ val expectedKeyGestureType: Int,
+ val expectedKeys: IntArray,
+ val expectedModifierState: Int,
+ val expectedActions: IntArray,
+ ) {
+ override fun toString(): String = name
+ }
+
+ @Keep
+ private fun keyGestureEventHandlerTestArguments(): Array<TestData> {
+ return arrayOf(
+ TestData(
+ "META + A -> Launch Assistant",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_A),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT,
+ intArrayOf(KeyEvent.KEYCODE_A),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "RECENT_APPS -> Show Overview",
+ intArrayOf(KeyEvent.KEYCODE_RECENT_APPS),
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
+ intArrayOf(KeyEvent.KEYCODE_RECENT_APPS),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "APP_SWITCH -> App Switch",
+ intArrayOf(KeyEvent.KEYCODE_APP_SWITCH),
+ KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
+ intArrayOf(KeyEvent.KEYCODE_APP_SWITCH),
+ 0,
+ intArrayOf(
+ KeyGestureEvent.ACTION_GESTURE_START,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ )
+ ),
+ TestData(
+ "META + H -> Go Home",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_H),
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
+ intArrayOf(KeyEvent.KEYCODE_H),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + ENTER -> Go Home",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_ENTER),
+ KeyGestureEvent.KEY_GESTURE_TYPE_HOME,
+ intArrayOf(KeyEvent.KEYCODE_ENTER),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + I -> Launch System Settings",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_I),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS,
+ intArrayOf(KeyEvent.KEYCODE_I),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + L -> Lock",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_L),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN,
+ intArrayOf(KeyEvent.KEYCODE_L),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + N -> Toggle Notification",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_N),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+ intArrayOf(KeyEvent.KEYCODE_N),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + CTRL + N -> Open Notes",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_N
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES,
+ intArrayOf(KeyEvent.KEYCODE_N),
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + CTRL + S -> Take Screenshot",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_S
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ intArrayOf(KeyEvent.KEYCODE_S),
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + DEL -> Back",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_DEL),
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
+ intArrayOf(KeyEvent.KEYCODE_DEL),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + ESC -> Back",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_ESCAPE),
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
+ intArrayOf(KeyEvent.KEYCODE_ESCAPE),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + DPAD_LEFT -> Back",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_DPAD_LEFT),
+ KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
+ intArrayOf(KeyEvent.KEYCODE_DPAD_LEFT),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + CTRL + DPAD_UP -> Multi Window Navigation",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_DPAD_UP
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION,
+ intArrayOf(KeyEvent.KEYCODE_DPAD_UP),
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + CTRL + DPAD_DOWN -> Desktop Mode",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_DPAD_DOWN
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE,
+ intArrayOf(KeyEvent.KEYCODE_DPAD_DOWN),
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + CTRL + DPAD_LEFT -> Splitscreen Navigation Left",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_DPAD_LEFT
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT,
+ intArrayOf(KeyEvent.KEYCODE_DPAD_LEFT),
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + CTRL + DPAD_RIGHT -> Splitscreen Navigation Right",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_CTRL_LEFT,
+ KeyEvent.KEYCODE_DPAD_RIGHT
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT,
+ intArrayOf(KeyEvent.KEYCODE_DPAD_RIGHT),
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + ALT + DPAD_LEFT -> Change Splitscreen Focus Left",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_DPAD_LEFT
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT,
+ intArrayOf(KeyEvent.KEYCODE_DPAD_LEFT),
+ KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + CTRL + DPAD_RIGHT -> Change Splitscreen Focus Right",
+ intArrayOf(
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_DPAD_RIGHT
+ ),
+ KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT,
+ intArrayOf(KeyEvent.KEYCODE_DPAD_RIGHT),
+ KeyEvent.META_META_ON or KeyEvent.META_ALT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "BRIGHTNESS_UP -> Brightness Up",
+ intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_UP),
+ KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_UP,
+ intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_UP),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "BRIGHTNESS_DOWN -> Brightness Down",
+ intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_DOWN),
+ KeyGestureEvent.KEY_GESTURE_TYPE_BRIGHTNESS_DOWN,
+ intArrayOf(KeyEvent.KEYCODE_BRIGHTNESS_DOWN),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "KEYBOARD_BACKLIGHT_UP -> Keyboard Backlight Up",
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP),
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_UP,
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "KEYBOARD_BACKLIGHT_DOWN -> Keyboard Backlight Down",
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN),
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_DOWN,
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "KEYBOARD_BACKLIGHT_TOGGLE -> Keyboard Backlight Toggle",
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE),
+ KeyGestureEvent.KEY_GESTURE_TYPE_KEYBOARD_BACKLIGHT_TOGGLE,
+ intArrayOf(KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ALL_APPS -> Open App Drawer",
+ intArrayOf(KeyEvent.KEYCODE_ALL_APPS),
+ KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS,
+ intArrayOf(KeyEvent.KEYCODE_ALL_APPS),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "NOTIFICATION -> Toggle Notification Panel",
+ intArrayOf(KeyEvent.KEYCODE_NOTIFICATION),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL,
+ intArrayOf(KeyEvent.KEYCODE_NOTIFICATION),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "LANGUAGE_SWITCH -> Switch Language Forward",
+ intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "SHIFT + LANGUAGE_SWITCH -> Switch Language Backward",
+ intArrayOf(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_LANGUAGE_SWITCH),
+ KeyGestureEvent.KEY_GESTURE_TYPE_LANGUAGE_SWITCH,
+ intArrayOf(KeyEvent.KEYCODE_LANGUAGE_SWITCH),
+ KeyEvent.META_SHIFT_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "SCREENSHOT -> Take Screenshot",
+ intArrayOf(KeyEvent.KEYCODE_SCREENSHOT),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT,
+ intArrayOf(KeyEvent.KEYCODE_SCREENSHOT),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META -> Open Apps Drawer",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT),
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS,
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + ALT -> Toggle Caps Lock",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_ALT_LEFT),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_ALT_LEFT),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ALT + META -> Toggle Caps Lock",
+ intArrayOf(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_META_LEFT),
+ KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK,
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_ALT_LEFT),
+ 0,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "META + TAB -> Open Overview",
+ intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_TAB),
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS,
+ intArrayOf(KeyEvent.KEYCODE_TAB),
+ KeyEvent.META_META_ON,
+ intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
+ ),
+ TestData(
+ "ALT + TAB -> Toggle Recent Apps Switcher",
+ intArrayOf(KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_TAB),
+ KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER,
+ intArrayOf(KeyEvent.KEYCODE_TAB),
+ KeyEvent.META_ALT_ON,
+ intArrayOf(
+ KeyGestureEvent.ACTION_GESTURE_START,
+ KeyGestureEvent.ACTION_GESTURE_COMPLETE
+ )
+ ),
+ )
+ }
+
+ @Test
+ @Parameters(method = "keyGestureEventHandlerTestArguments")
+ fun testKeyGestures(test: TestData) {
+ val handler = KeyGestureHandler { event, _ ->
+ handleEvents.add(KeyGestureEvent(event))
+ true
+ }
+ keyGestureController.registerKeyGestureHandler(handler, 0)
+ handleEvents.clear()
+
+ sendKeys(test.keys, /* assertAllConsumed = */ false)
+
+ assertEquals(
+ "Test: $test doesn't produce correct number of key gesture events",
+ test.expectedActions.size,
+ handleEvents.size
+ )
+ for (i in handleEvents.indices) {
+ val event = handleEvents[i]
+ assertArrayEquals(
+ "Test: $test doesn't produce correct key gesture keycodes",
+ test.expectedKeys,
+ event.keycodes
+ )
+ assertEquals(
+ "Test: $test doesn't produce correct key gesture modifier state",
+ test.expectedModifierState,
+ event.modifierState
+ )
+ assertEquals(
+ "Test: $test doesn't produce correct key gesture type",
+ test.expectedKeyGestureType,
+ event.keyGestureType
+ )
+ assertEquals(
+ "Test: $test doesn't produce correct key gesture action",
+ test.expectedActions[i],
+ event.action
+ )
+ }
+
+ keyGestureController.unregisterKeyGestureHandler(handler, 0)
+ }
+
+ @Test
+ fun testKeycodesFullyConsumed_irrespectiveOfHandlers() {
+ val testKeys = intArrayOf(
+ KeyEvent.KEYCODE_RECENT_APPS,
+ KeyEvent.KEYCODE_APP_SWITCH,
+ KeyEvent.KEYCODE_BRIGHTNESS_UP,
+ KeyEvent.KEYCODE_BRIGHTNESS_DOWN,
+ KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN,
+ KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP,
+ KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE,
+ KeyEvent.KEYCODE_ALL_APPS,
+ KeyEvent.KEYCODE_NOTIFICATION,
+ KeyEvent.KEYCODE_SETTINGS,
+ KeyEvent.KEYCODE_LANGUAGE_SWITCH,
+ KeyEvent.KEYCODE_SCREENSHOT,
+ KeyEvent.KEYCODE_META_LEFT,
+ KeyEvent.KEYCODE_META_RIGHT,
+ KeyEvent.KEYCODE_ASSIST,
+ KeyEvent.KEYCODE_VOICE_ASSIST,
+ KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY,
+ KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY,
+ KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY,
+ KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL,
+ )
+
+ val handler = KeyGestureHandler { _, _ -> false }
+ keyGestureController.registerKeyGestureHandler(handler, 0)
+
+ for (key in testKeys) {
+ sendKeys(intArrayOf(key), /* assertAllConsumed = */ true)
+ }
+ }
+
+ private fun sendKeys(testKeys: IntArray, assertAllConsumed: Boolean) {
+ var metaState = 0
+ for (key in testKeys) {
+ val downEvent = KeyEvent(
+ /* downTime = */0, /* eventTime = */ 0, KeyEvent.ACTION_DOWN, key,
+ 0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
+ 0 /*flags*/, InputDevice.SOURCE_KEYBOARD
+ )
+ val consumed =
+ keyGestureController.interceptKeyBeforeDispatching(null, downEvent, 0) == -1L
+ if (assertAllConsumed) {
+ assertTrue(
+ "interceptKeyBeforeDispatching should consume all events $downEvent",
+ consumed
+ )
+ }
+ metaState = metaState or MODIFIER.getOrDefault(key, 0)
+
+ downEvent.recycle()
+ testLooper.dispatchAll()
+ }
+
+ for (key in testKeys.reversed()) {
+ val upEvent = KeyEvent(
+ /* downTime = */0, /* eventTime = */ 0, KeyEvent.ACTION_UP, key,
+ 0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
+ 0 /*flags*/, InputDevice.SOURCE_KEYBOARD
+ )
+ val consumed =
+ keyGestureController.interceptKeyBeforeDispatching(null, upEvent, 0) == -1L
+ if (assertAllConsumed) {
+ assertTrue(
+ "interceptKeyBeforeDispatching should consume all events $upEvent",
+ consumed
+ )
+ }
+
+ upEvent.recycle()
+ testLooper.dispatchAll()
+ }
+ }
+
inner class KeyGestureEventListener : IKeyGestureEventListener.Stub() {
override fun onKeyGestureEvent(event: AidlKeyGestureEvent) {
events.add(KeyGestureEvent(event))
diff --git a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
index 0719686..681b7f2 100644
--- a/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
+++ b/tests/Input/src/com/android/server/input/debug/TouchpadDebugViewTest.java
@@ -36,6 +36,7 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
+import android.widget.TextView;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -327,4 +328,17 @@
assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.BLUE);
}
+
+ @Test
+ public void testTouchpadGesture() {
+ int gestureType = 3;
+ TextView child = mTouchpadDebugView.getGestureInfoView();
+
+ mTouchpadDebugView.updateGestureInfo(gestureType, TOUCHPAD_DEVICE_ID);
+ assertEquals(child.getText().toString(), TouchpadDebugView.getGestureText(gestureType));
+
+ gestureType = 6;
+ mTouchpadDebugView.updateGestureInfo(gestureType, TOUCHPAD_DEVICE_ID);
+ assertEquals(child.getText().toString(), TouchpadDebugView.getGestureText(gestureType));
+ }
}
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
index d32cedb..cd6ab30 100644
--- a/tests/Input/src/com/android/test/input/AnrTest.kt
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -166,12 +166,12 @@
val displayManager =
instrumentation.context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val display = displayManager.getDisplay(obj.getDisplayId())
- val touchScreen = UinputTouchScreen(instrumentation, display)
-
val rect: Rect = obj.visibleBounds
- val pointer = touchScreen.touchDown(rect.centerX(), rect.centerY())
- pointer.lift()
- touchScreen.close()
+ UinputTouchScreen(instrumentation, display).use { touchScreen ->
+ touchScreen
+ .touchDown(rect.centerX(), rect.centerY())
+ .lift()
+ }
}
private fun triggerAnr() {
diff --git a/tests/Input/src/com/android/test/input/CaptureEventActivity.kt b/tests/Input/src/com/android/test/input/CaptureEventActivity.kt
new file mode 100644
index 0000000..d54e3470
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/CaptureEventActivity.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2024 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.test.input
+
+import android.app.Activity
+import android.os.Bundle
+import android.view.InputEvent
+import android.view.KeyEvent
+import android.view.MotionEvent
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.assertNull
+
+class CaptureEventActivity : Activity() {
+ private val events = LinkedBlockingQueue<InputEvent>()
+ var shouldHandleKeyEvents = true
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // Set the fixed orientation if requested
+ if (intent.hasExtra(EXTRA_FIXED_ORIENTATION)) {
+ val orientation = intent.getIntExtra(EXTRA_FIXED_ORIENTATION, 0)
+ setRequestedOrientation(orientation)
+ }
+
+ // Set the flag if requested
+ if (intent.hasExtra(EXTRA_WINDOW_FLAGS)) {
+ val flags = intent.getIntExtra(EXTRA_WINDOW_FLAGS, 0)
+ window.addFlags(flags)
+ }
+ }
+
+ override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
+ events.add(KeyEvent(event))
+ return shouldHandleKeyEvents
+ }
+
+ override fun dispatchTrackballEvent(ev: MotionEvent?): Boolean {
+ events.add(MotionEvent.obtain(ev))
+ return true
+ }
+
+ fun getInputEvent(): InputEvent? {
+ return events.poll(5, TimeUnit.SECONDS)
+ }
+
+ fun hasReceivedEvents(): Boolean {
+ return !events.isEmpty()
+ }
+
+ fun assertNoEvents() {
+ val event = events.poll(100, TimeUnit.MILLISECONDS)
+ assertNull("Expected no events, but received $event", event)
+ }
+
+ companion object {
+ const val EXTRA_FIXED_ORIENTATION = "fixed_orientation"
+ const val EXTRA_WINDOW_FLAGS = "window_flags"
+ }
+}
diff --git a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
new file mode 100644
index 0000000..c61a250
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2024 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.test.input
+
+import android.Manifest.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY
+import android.app.Instrumentation
+import android.cts.input.EventVerifier
+import android.graphics.PointF
+import android.hardware.input.InputManager
+import android.os.ParcelFileDescriptor
+import android.util.Log
+import android.util.Size
+import android.view.InputEvent
+import android.view.MotionEvent
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.cts.input.BatchedEventSplitter
+import com.android.cts.input.InputJsonParser
+import com.android.cts.input.VirtualDisplayActivityScenario
+import com.android.cts.input.inputeventmatchers.isResampled
+import com.android.cts.input.inputeventmatchers.withButtonState
+import com.android.cts.input.inputeventmatchers.withHistorySize
+import com.android.cts.input.inputeventmatchers.withMotionAction
+import com.android.cts.input.inputeventmatchers.withPressure
+import com.android.cts.input.inputeventmatchers.withRawCoords
+import com.android.cts.input.inputeventmatchers.withSource
+import junit.framework.Assert.fail
+import org.hamcrest.Matchers.allOf
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Integration tests for the input pipeline that replays recording taken from physical input devices
+ * at the evdev interface level, and makes assertions on the events that are received by a test app.
+ *
+ * These tests associate the playback input device with a virtual display to make these tests
+ * agnostic to the device form factor.
+ *
+ * New recordings can be taken using the `evemu-record` shell command.
+ */
+@RunWith(Parameterized::class)
+class UinputRecordingIntegrationTests {
+
+ companion object {
+ /**
+ * Add new test cases by adding a new [TestData] to the following list.
+ */
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun data(): Iterable<Any> =
+ listOf(
+ TestData(
+ "GooglePixelTabletTouchscreen", R.raw.google_pixel_tablet_touchscreen,
+ R.raw.google_pixel_tablet_touchscreen_events, Size(1600, 2560),
+ vendorId = 0x0603, productId = 0x7806
+ ),
+ )
+
+ /**
+ * Use the debug mode to see the JSON-encoded received events in logcat.
+ */
+ const val DEBUG_RECEIVED_EVENTS = false
+
+ const val INPUT_DEVICE_SOURCE_ALL = -1
+ val TAG = UinputRecordingIntegrationTests::class.java.simpleName
+ }
+
+ class TestData(
+ val name: String,
+ val uinputRecordingResource: Int,
+ val expectedEventsResource: Int,
+ val displaySize: Size,
+ val vendorId: Int,
+ val productId: Int,
+ ) {
+ override fun toString(): String = name
+ }
+
+ private lateinit var instrumentation: Instrumentation
+ private lateinit var parser: InputJsonParser
+
+ @get:Rule
+ val testName = TestName()
+
+ @Parameterized.Parameter(0)
+ lateinit var testData: TestData
+
+ @Before
+ fun setUp() {
+ instrumentation = InstrumentationRegistry.getInstrumentation()
+ parser = InputJsonParser(instrumentation.context)
+ }
+
+ @Test
+ fun testEvemuRecording() {
+ VirtualDisplayActivityScenario.AutoClose<CaptureEventActivity>(
+ testName,
+ size = testData.displaySize
+ ).use { scenario ->
+ scenario.activity.window.decorView.requestUnbufferedDispatch(INPUT_DEVICE_SOURCE_ALL)
+
+ try {
+ instrumentation.uiAutomation.adoptShellPermissionIdentity(
+ ASSOCIATE_INPUT_DEVICE_TO_DISPLAY,
+ )
+
+ val inputPort = "uinput:1:${testData.vendorId}:${testData.productId}"
+ val inputManager =
+ instrumentation.context.getSystemService(InputManager::class.java)!!
+ try {
+ inputManager.addUniqueIdAssociationByPort(
+ inputPort,
+ scenario.virtualDisplay.display.uniqueId!!,
+ )
+
+ injectUinputEvents().use {
+ if (DEBUG_RECEIVED_EVENTS) {
+ printReceivedEventsToLogcat(scenario.activity)
+ fail("Test cannot pass in debug mode!")
+ }
+
+ val verifier = EventVerifier(
+ BatchedEventSplitter { scenario.activity.getInputEvent() }
+ )
+ verifyEvents(verifier)
+ scenario.activity.assertNoEvents()
+ }
+ } finally {
+ inputManager.removeUniqueIdAssociationByPort(inputPort)
+ }
+ } finally {
+ instrumentation.uiAutomation.dropShellPermissionIdentity()
+ }
+ }
+ }
+
+ private fun printReceivedEventsToLogcat(activity: CaptureEventActivity) {
+ val getNextEvent = BatchedEventSplitter { activity.getInputEvent() }
+ var receivedEvent: InputEvent? = getNextEvent()
+ while (receivedEvent != null) {
+ Log.d(TAG,
+ parser.encodeEvent(receivedEvent)?.toString()
+ ?: "(Failed to encode received event)"
+ )
+ receivedEvent = getNextEvent()
+ }
+ }
+
+ /**
+ * Plays back the evemu recording associated with the current test case by injecting it via
+ * the `uinput` shell command in interactive mode. The recording playback will begin
+ * immediately, and the shell command (and the associated input device) will remain alive
+ * until the returned [AutoCloseable] is closed.
+ */
+ private fun injectUinputEvents(): AutoCloseable {
+ val fds = instrumentation.uiAutomation!!.executeShellCommandRw("uinput -")
+ // We do not need to use stdout in this test.
+ fds[0].close()
+
+ return ParcelFileDescriptor.AutoCloseOutputStream(fds[1]).also { stdin ->
+ instrumentation.context.resources.openRawResource(
+ testData.uinputRecordingResource,
+ ).use { inputStream ->
+ stdin.write(inputStream.readBytes())
+
+ // TODO(b/367419268): Remove extra event injection when uinput parsing is fixed.
+ // Inject an extra sync event with an arbitrarily large timestamp, because the
+ // uinput command will not process the last event until either the next event is
+ // parsed, or fd is closed. Injecting this sync allows us complete injection of
+ // the evemu recording and extend the lifetime of the input device by keeping this
+ // fd open.
+ stdin.write("\nE: 9999.99 0 0 0\n".toByteArray())
+ stdin.flush()
+ }
+ }
+ }
+
+ private fun verifyEvents(verifier: EventVerifier) {
+ val uinputTestData = parser.getUinputTestData(testData.expectedEventsResource)
+ for (test in uinputTestData) {
+ for ((index, expectedEvent) in test.events.withIndex()) {
+ if (expectedEvent is MotionEvent) {
+ verifier.assertReceivedMotion(
+ allOf(
+ withMotionAction(expectedEvent.action),
+ withSource(expectedEvent.source),
+ withButtonState(expectedEvent.buttonState),
+ withRawCoords(PointF(expectedEvent.rawX, expectedEvent.rawY)),
+ withPressure(expectedEvent.pressure),
+ isResampled(false),
+ withHistorySize(0),
+ ),
+ "${test.name}: Expected event at index $index",
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/tests/Tracing/Android.bp b/tests/Tracing/Android.bp
new file mode 100644
index 0000000..5a7f12f
--- /dev/null
+++ b/tests/Tracing/Android.bp
@@ -0,0 +1,33 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_team: "trendy_team_windowing_tools",
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "TracingTests",
+ proto: {
+ type: "nano",
+ },
+ // Include some source files directly to be able to access package members
+ srcs: ["src/**/*.java"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "junit",
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "truth",
+ "platform-test-annotations",
+ "flickerlib-parsers",
+ "perfetto_trace_java_protos",
+ "flickerlib-trace_processor_shell",
+ ],
+ java_resource_dirs: ["res"],
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+}
diff --git a/tests/Tracing/AndroidManifest.xml b/tests/Tracing/AndroidManifest.xml
new file mode 100644
index 0000000..7254f81
--- /dev/null
+++ b/tests/Tracing/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tracing.tests">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.BIND_WALLPAPER"/>
+ <!-- Allow the test to connect to perfetto trace processor -->
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <application
+ android:requestLegacyExternalStorage="true"
+ android:networkSecurityConfig="@xml/network_security_config">
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.tracing.tests"
+ android:label="Tracing Tests"/>
+</manifest>
diff --git a/tests/Tracing/AndroidTest.xml b/tests/Tracing/AndroidTest.xml
new file mode 100644
index 0000000..9a40420
--- /dev/null
+++ b/tests/Tracing/AndroidTest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<configuration description="Runs tests for tracing classes/utilities.">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="TracingTests.apk" />
+ </target_preparer>
+
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="framework-base-presubmit" />
+ <option name="test-tag" value="TracingTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.tracing.tests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.tracing.tests/files"/>
+ <option name="collect-on-run-ended-only" value="true"/>
+ <option name="clean-up" value="true"/>
+ </metrics_collector>
+</configuration>
\ No newline at end of file
diff --git a/tests/Internal/src/com/android/internal/protolog/OWNERS b/tests/Tracing/OWNERS
similarity index 80%
rename from tests/Internal/src/com/android/internal/protolog/OWNERS
rename to tests/Tracing/OWNERS
index 18cf2be..4a50338 100644
--- a/tests/Internal/src/com/android/internal/protolog/OWNERS
+++ b/tests/Tracing/OWNERS
@@ -1,3 +1,3 @@
-# ProtoLog owners
+# Tracing owners
# Bug component: 1157642
include platform/development:/tools/winscope/OWNERS
diff --git a/tests/Tracing/TEST_MAPPING b/tests/Tracing/TEST_MAPPING
new file mode 100644
index 0000000..7f58fce
--- /dev/null
+++ b/tests/Tracing/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "TracingTests"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/Tracing/res/xml/network_security_config.xml b/tests/Tracing/res/xml/network_security_config.xml
new file mode 100644
index 0000000..fdf1dbb
--- /dev/null
+++ b/tests/Tracing/res/xml/network_security_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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.
+ -->
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>
diff --git a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
similarity index 99%
rename from tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
rename to tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
index 9657225..8913e8c 100644
--- a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
@@ -180,7 +180,6 @@
verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
LogLevel.INFO), eq("test 5"));
- verify(mReader, never()).getViewerString(anyLong());
}
@Test
diff --git a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogViewerConfigReaderTest.java b/tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogViewerConfigReaderTest.java
similarity index 100%
rename from tests/Internal/src/com/android/internal/protolog/LegacyProtoLogViewerConfigReaderTest.java
rename to tests/Tracing/src/com/android/internal/protolog/LegacyProtoLogViewerConfigReaderTest.java
diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
similarity index 100%
rename from tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
rename to tests/Tracing/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
similarity index 86%
rename from tests/Internal/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
rename to tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
index aba6722..be0c7da 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.times;
+import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import org.junit.Test;
@@ -44,6 +45,8 @@
ProtoLogConfigurationService mProtoLogConfigurationService;
@Mock
PrintWriter mPrintWriter;
+ @Mock
+ Binder mMockBinder;
@Test
public void printsHelpForAllAvailableCommands() {
@@ -70,7 +73,7 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "groups", "list" });
Mockito.verify(mPrintWriter, times(1))
@@ -84,7 +87,7 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "groups" });
Mockito.verify(mPrintWriter, times(1))
@@ -99,7 +102,7 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "groups", "status", "MY_GROUP" });
Mockito.verify(mPrintWriter, times(1))
@@ -114,7 +117,7 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "groups", "status", "MY_GROUP" });
Mockito.verify(mPrintWriter, times(1))
@@ -128,7 +131,7 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "groups", "status" });
Mockito.verify(mPrintWriter, times(1))
@@ -140,7 +143,7 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat" });
Mockito.verify(mPrintWriter, times(1))
@@ -152,11 +155,11 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP" });
Mockito.verify(mProtoLogConfigurationService).enableProtoLogToLogcat("MY_GROUP");
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err,
new String[] { "logcat", "enable", "MY_GROUP", "MY_OTHER_GROUP" });
Mockito.verify(mProtoLogConfigurationService)
@@ -168,11 +171,11 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP" });
Mockito.verify(mProtoLogConfigurationService).disableProtoLogToLogcat("MY_GROUP");
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err,
new String[] { "logcat", "disable", "MY_GROUP", "MY_OTHER_GROUP" });
Mockito.verify(mProtoLogConfigurationService)
@@ -184,7 +187,7 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat", "enable" });
Mockito.verify(mPrintWriter).println(contains("Incomplete command"));
}
@@ -194,7 +197,7 @@
final ProtoLogCommandHandler cmdHandler =
new ProtoLogCommandHandler(mProtoLogConfigurationService, mPrintWriter);
- cmdHandler.exec(mProtoLogConfigurationService, FileDescriptor.in, FileDescriptor.out,
+ cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out,
FileDescriptor.err, new String[] { "logcat", "disable" });
Mockito.verify(mPrintWriter).println(contains("Incomplete command"));
}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
similarity index 100%
rename from tests/Internal/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
rename to tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogImplTest.java
similarity index 100%
rename from tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
rename to tests/Tracing/src/com/android/internal/protolog/ProtoLogImplTest.java
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogTest.java
similarity index 100%
rename from tests/Internal/src/com/android/internal/protolog/ProtoLogTest.java
rename to tests/Tracing/src/com/android/internal/protolog/ProtoLogTest.java
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
similarity index 98%
rename from tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
rename to tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
index be0e8bc..28d7b42 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
@@ -27,7 +27,6 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import perfetto.protos.Protolog;
import perfetto.protos.ProtologCommon;
@Presubmit
@@ -48,7 +47,7 @@
.setTag(TEST_GROUP_TAG)
).addGroups(
perfetto.protos.Protolog.ProtoLogViewerConfig.Group.newBuilder()
- .setId(1)
+ .setId(2)
.setName(OTHER_TEST_GROUP_NAME)
.setTag(OTHER_TEST_GROUP_TAG)
).addMessages(
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtologDataSourceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
similarity index 98%
rename from tests/Internal/src/com/android/internal/protolog/ProtologDataSourceTest.java
rename to tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
index 9a062e3..ce519b7a 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtologDataSourceTest.java
+++ b/tests/Tracing/src/com/android/internal/protolog/ProtologDataSourceTest.java
@@ -67,7 +67,8 @@
@Test
public void allEnabledTraceMode() {
- final ProtoLogDataSource ds = new ProtoLogDataSource((idx, c) -> {}, () -> {}, (idx, c) -> {});
+ final ProtoLogDataSource ds =
+ new ProtoLogDataSource((idx, c) -> {}, () -> {}, (idx, c) -> {});
final ProtoLogDataSource.TlsState tlsState = createTlsState(
DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
diff --git a/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java b/tests/Tracing/src/com/android/internal/protolog/common/LogDataTypeTest.java
similarity index 100%
rename from tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java
rename to tests/Tracing/src/com/android/internal/protolog/common/LogDataTypeTest.java
diff --git a/tests/TrustTests/TEST_MAPPING b/tests/TrustTests/TEST_MAPPING
index 23923ee..b0dd551 100644
--- a/tests/TrustTests/TEST_MAPPING
+++ b/tests/TrustTests/TEST_MAPPING
@@ -1,28 +1,12 @@
{
"presubmit": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
],
"trust-tablet": [
{
- "name": "TrustTests",
- "options": [
- {
- "include-filter": "android.trust.test"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
+ "name": "TrustTests_trust_test"
}
]
}
\ No newline at end of file
diff --git a/tests/UsbManagerTests/Android.bp b/tests/UsbManagerTests/Android.bp
index 2909e66..331a21a 100644
--- a/tests/UsbManagerTests/Android.bp
+++ b/tests/UsbManagerTests/Android.bp
@@ -44,7 +44,7 @@
"libstaticjvmtiagent",
],
libs: [
- "android.test.mock",
+ "android.test.mock.stubs.system",
],
certificate: "platform",
platform_apis: true,
diff --git a/tests/utils/testutils/TEST_MAPPING b/tests/utils/testutils/TEST_MAPPING
index 52fd5a8..71e9ad3 100644
--- a/tests/utils/testutils/TEST_MAPPING
+++ b/tests/utils/testutils/TEST_MAPPING
@@ -1,18 +1,7 @@
{
"presubmit": [
{
- "name": "frameworks-base-testutils-tests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.LargeTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
+ "name": "frameworks-base-testutils-tests"
}
],
"postsubmit": [
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 580efe12..4cb7c91 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -146,6 +146,8 @@
private static final LinkProperties TEST_LP_1 = new LinkProperties();
private static final LinkProperties TEST_LP_2 = new LinkProperties();
+ private static final int ACTIVE_MODEM_COUNT = 2;
+
static {
TEST_LP_1.setInterfaceName(TEST_IFACE_NAME);
TEST_LP_2.setInterfaceName(TEST_IFACE_NAME_2);
@@ -233,6 +235,7 @@
setupSystemService(mMockContext, mUserManager, Context.USER_SERVICE, UserManager.class);
doReturn(TEST_USER_HANDLE).when(mUserManager).getMainUser();
+ doReturn(ACTIVE_MODEM_COUNT).when(mTelMgr).getActiveModemCount();
doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
diff --git a/tools/systemfeatures/Android.bp b/tools/systemfeatures/Android.bp
index aca25eb..a9e6328 100644
--- a/tools/systemfeatures/Android.bp
+++ b/tools/systemfeatures/Android.bp
@@ -5,6 +5,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_system_performance",
}
java_library_host {
@@ -25,8 +26,6 @@
static_libs: ["systemfeatures-gen-lib"],
}
-// TODO(b/203143243): Add golden diff test for generated sources.
-// Functional runtime behavior is covered in systemfeatures-gen-tests.
genrule {
name: "systemfeatures-gen-tests-srcs",
cmd: "$(location systemfeatures-gen-tool) com.android.systemfeatures.RwNoFeatures --readonly=false > $(location RwNoFeatures.java) && " +
@@ -42,11 +41,12 @@
tools: ["systemfeatures-gen-tool"],
}
+// Functional runtime behavior testing.
java_test_host {
name: "systemfeatures-gen-tests",
test_suites: ["general-tests"],
srcs: [
- "tests/**/*.java",
+ "tests/src/**/*.java",
":systemfeatures-gen-tests-srcs",
],
test_options: {
@@ -61,3 +61,33 @@
"truth",
],
}
+
+// Rename the goldens as they may be copied into the source tree, and we don't
+// need or want the usual `.java` linting (e.g., copyright checks).
+genrule {
+ name: "systemfeatures-gen-tests-golden-srcs",
+ cmd: "for f in $(in); do cp $$f $(genDir)/tests/gen/$$(basename $$f).gen; done",
+ srcs: [":systemfeatures-gen-tests-srcs"],
+ out: [
+ "tests/gen/RwNoFeatures.java.gen",
+ "tests/gen/RoNoFeatures.java.gen",
+ "tests/gen/RwFeatures.java.gen",
+ "tests/gen/RoFeatures.java.gen",
+ ],
+}
+
+// Golden output testing. Golden sources can be updated via:
+// $ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/tests/golden_test.sh --update
+sh_test_host {
+ name: "systemfeatures-gen-golden-tests",
+ src: "tests/golden_test.sh",
+ filename: "systemfeatures-gen-golden-tests.sh",
+ test_config: "tests/systemfeatures-gen-golden-tests.xml",
+ data: [
+ "tests/golden/**/*.java*",
+ ":systemfeatures-gen-tests-golden-srcs",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
index e537ffc..5df453d 100644
--- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
@@ -142,6 +142,10 @@
// TODO(b/203143243): Add validation of build vs runtime values to ensure consistency.
JavaFile.builder(outputClassName.packageName(), classBuilder.build())
+ .indent(" ")
+ .skipJavaLangImports(true)
+ .addFileComment("This file is auto-generated. DO NOT MODIFY.\n")
+ .addFileComment("Args: ${args.joinToString(" \\\n ")}")
.build()
.writeTo(System.out)
}
@@ -178,6 +182,7 @@
val methodBuilder =
MethodSpec.methodBuilder(methodName)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+ .addJavadoc("Check for ${feature.name}.\n\n@hide")
.returns(Boolean::class.java)
.addParameter(CONTEXT_CLASS, "context")
@@ -228,6 +233,7 @@
MethodSpec.methodBuilder("maybeHasFeature")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addAnnotation(ClassName.get("android.annotation", "Nullable"))
+ .addJavadoc("@hide")
.returns(Boolean::class.javaObjectType) // Use object type for nullability
.addParameter(String::class.java, "featureName")
.addParameter(Int::class.java, "version")
diff --git a/tools/systemfeatures/tests/golden/RoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
new file mode 100644
index 0000000..724639b
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
@@ -0,0 +1,88 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RoFeatures \
+// --readonly=true \
+// --feature=WATCH:1 \
+// --feature=WIFI:0 \
+// --feature=VULKAN:-1 \
+// --feature=AUTO: \
+// --feature-apis=WATCH,PC
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import com.android.aconfig.annotations.AssumeFalseForR8;
+import com.android.aconfig.annotations.AssumeTrueForR8;
+
+/**
+ * @hide
+ */
+public final class RoFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ @AssumeTrueForR8
+ public static boolean hasFeatureWatch(Context context) {
+ return true;
+ }
+
+ /**
+ * Check for FEATURE_PC.
+ *
+ * @hide
+ */
+ public static boolean hasFeaturePc(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_PC);
+ }
+
+ /**
+ * Check for FEATURE_WIFI.
+ *
+ * @hide
+ */
+ @AssumeTrueForR8
+ public static boolean hasFeatureWifi(Context context) {
+ return true;
+ }
+
+ /**
+ * Check for FEATURE_VULKAN.
+ *
+ * @hide
+ */
+ @AssumeFalseForR8
+ public static boolean hasFeatureVulkan(Context context) {
+ return false;
+ }
+
+ /**
+ * Check for FEATURE_AUTO.
+ *
+ * @hide
+ */
+ @AssumeFalseForR8
+ public static boolean hasFeatureAuto(Context context) {
+ return false;
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ switch (featureName) {
+ case PackageManager.FEATURE_WATCH: return 1 >= version;
+ case PackageManager.FEATURE_WIFI: return 0 >= version;
+ case PackageManager.FEATURE_VULKAN: return -1 >= version;
+ case PackageManager.FEATURE_AUTO: return false;
+ default: break;
+ }
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
new file mode 100644
index 0000000..59c5b4e
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
@@ -0,0 +1,35 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RoNoFeatures \
+// --readonly=true \
+// --feature-apis=WATCH
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * @hide
+ */
+public final class RoNoFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWatch(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WATCH);
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RwFeatures.java.gen b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
new file mode 100644
index 0000000..6f89759
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
@@ -0,0 +1,65 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RwFeatures \
+// --readonly=false \
+// --feature=WATCH:1 \
+// --feature=WIFI:0 \
+// --feature=VULKAN:-1 \
+// --feature=AUTO:
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+/**
+ * @hide
+ */
+public final class RwFeatures {
+ /**
+ * Check for FEATURE_WATCH.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWatch(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WATCH);
+ }
+
+ /**
+ * Check for FEATURE_WIFI.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureWifi(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_WIFI);
+ }
+
+ /**
+ * Check for FEATURE_VULKAN.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureVulkan(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_VULKAN);
+ }
+
+ /**
+ * Check for FEATURE_AUTO.
+ *
+ * @hide
+ */
+ public static boolean hasFeatureAuto(Context context) {
+ return hasFeatureFallback(context, PackageManager.FEATURE_AUTO);
+ }
+
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
new file mode 100644
index 0000000..2111d56
--- /dev/null
+++ b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
@@ -0,0 +1,24 @@
+// This file is auto-generated. DO NOT MODIFY.
+// Args: com.android.systemfeatures.RwNoFeatures \
+// --readonly=false
+package com.android.systemfeatures;
+
+import android.annotation.Nullable;
+import android.content.Context;
+
+/**
+ * @hide
+ */
+public final class RwNoFeatures {
+ private static boolean hasFeatureFallback(Context context, String featureName) {
+ return context.getPackageManager().hasSystemFeature(featureName, 0);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Boolean maybeHasFeature(String featureName, int version) {
+ return null;
+ }
+}
diff --git a/tools/systemfeatures/tests/golden_test.sh b/tools/systemfeatures/tests/golden_test.sh
new file mode 100755
index 0000000..c249254
--- /dev/null
+++ b/tools/systemfeatures/tests/golden_test.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2024 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.
+
+set -e
+
+GEN_DIR="tests/gen"
+GOLDEN_DIR="tests/golden"
+
+if [[ $(basename $0) == "golden_test.sh" ]]; then
+ # We're running via command-line, so we need to:
+ # 1) manually update generated srcs
+ # 2) use absolute paths
+ if [ -z $ANDROID_BUILD_TOP ]; then
+ echo "You need to source and lunch before you can use this script directly."
+ exit 1
+ fi
+ GEN_DIR="$ANDROID_BUILD_TOP/out/soong/.intermediates/frameworks/base/tools/systemfeatures/systemfeatures-gen-tests-golden-srcs/gen/$GEN_DIR"
+ GOLDEN_DIR="$ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/$GOLDEN_DIR"
+ rm -rf "$GEN_DIR"
+ "$ANDROID_BUILD_TOP"/build/soong/soong_ui.bash --make-mode systemfeatures-gen-tests-golden-srcs
+fi
+
+if [[ "$1" == "--update" ]]; then
+ rm -rf "$GOLDEN_DIR"
+ cp -R "$GEN_DIR" "$GOLDEN_DIR"
+ echo "Updated golden test files."
+else
+ echo "Running diff from test output against golden test files..."
+ if diff -ruN "$GOLDEN_DIR" "$GEN_DIR" ; then
+ echo "No changes."
+ else
+ echo
+ echo "----------------------------------------------------------------------------------------"
+ echo "If changes look OK, run:"
+ echo " \$ANDROID_BUILD_TOP/frameworks/base/tools/systemfeatures/tests/golden_test.sh --update"
+ echo "----------------------------------------------------------------------------------------"
+ exit 1
+ fi
+fi
diff --git a/tools/systemfeatures/tests/Context.java b/tools/systemfeatures/tests/src/Context.java
similarity index 100%
rename from tools/systemfeatures/tests/Context.java
rename to tools/systemfeatures/tests/src/Context.java
diff --git a/tools/systemfeatures/tests/PackageManager.java b/tools/systemfeatures/tests/src/PackageManager.java
similarity index 100%
rename from tools/systemfeatures/tests/PackageManager.java
rename to tools/systemfeatures/tests/src/PackageManager.java
diff --git a/tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
similarity index 100%
rename from tools/systemfeatures/tests/SystemFeaturesGeneratorTest.java
rename to tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
diff --git a/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml b/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml
new file mode 100644
index 0000000..e3a5841
--- /dev/null
+++ b/tools/systemfeatures/tests/systemfeatures-gen-golden-tests.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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="Runs systemfeatures-gen golden diff test">
+ <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
+ <option name="binary" value="systemfeatures-gen-golden-tests.sh"/>
+ </test>
+</configuration>
diff --git a/wifi/java/src/android/net/wifi/WifiMigration.java b/wifi/java/src/android/net/wifi/WifiMigration.java
index 7df1d4b..f1850dd 100644
--- a/wifi/java/src/android/net/wifi/WifiMigration.java
+++ b/wifi/java/src/android/net/wifi/WifiMigration.java
@@ -100,6 +100,39 @@
public @interface UserStoreFileId { }
/**
+ * Keystore migration was completed successfully.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_LEGACY_KEYSTORE_TO_WIFI_BLOBSTORE_MIGRATION_READ_ONLY)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE = 0;
+
+ /**
+ * Keystore migration was not needed.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_LEGACY_KEYSTORE_TO_WIFI_BLOBSTORE_MIGRATION_READ_ONLY)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED = 1;
+
+ /**
+ * Keystore migration failed because an exception was encountered.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_LEGACY_KEYSTORE_TO_WIFI_BLOBSTORE_MIGRATION_READ_ONLY)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "KEYSTORE_MIGRATION_" }, value = {
+ KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE,
+ KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
+ KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface KeystoreMigrationStatus { }
+
+ /**
* Mapping of Store file Id to Store file names.
*
* NOTE: This is the default path for the files on AOSP devices. If the OEM has modified
@@ -572,14 +605,17 @@
/**
* Migrate any certificates in Legacy Keystore to the newer WifiBlobstore database.
*
+ * If there are no certificates to migrate, this method will return immediately.
+ *
* @hide
*/
@FlaggedApi(Flags.FLAG_LEGACY_KEYSTORE_TO_WIFI_BLOBSTORE_MIGRATION_READ_ONLY)
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static void migrateLegacyKeystoreToWifiBlobstore() {
+ public static @KeystoreMigrationStatus int migrateLegacyKeystoreToWifiBlobstore() {
if (!WifiBlobStore.supplicantCanAccessBlobstore()) {
+ // Supplicant cannot access WifiBlobstore, so keep the certs in Legacy Keystore
Log.i(TAG, "Avoiding migration since supplicant cannot access WifiBlobstore");
- return;
+ return KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED;
}
final long identity = Binder.clearCallingIdentity();
try {
@@ -587,7 +623,7 @@
String[] legacyAliases = legacyKeystore.list("", Process.WIFI_UID);
if (legacyAliases == null || legacyAliases.length == 0) {
Log.i(TAG, "No aliases need to be migrated");
- return;
+ return KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED;
}
WifiBlobStore wifiBlobStore = WifiBlobStore.getInstance();
@@ -605,14 +641,17 @@
legacyKeystore.remove(legacyAlias, Process.WIFI_UID);
}
Log.i(TAG, "Successfully migrated aliases from Legacy Keystore");
+ return KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE;
} catch (ServiceSpecificException e) {
if (e.errorCode == ILegacyKeystore.ERROR_SYSTEM_ERROR) {
Log.i(TAG, "Legacy Keystore service has been deprecated");
- } else {
- Log.e(TAG, "Encountered an exception while migrating aliases. " + e);
+ return KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED;
}
+ Log.e(TAG, "Encountered a ServiceSpecificException while migrating aliases. " + e);
+ return KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION;
} catch (Exception e) {
Log.e(TAG, "Encountered an exception while migrating aliases. " + e);
+ return KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION;
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/wifi/tests/src/android/net/wifi/WifiMigrationTest.java b/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
index d95069d..0aa299f 100644
--- a/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiMigrationTest.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -27,6 +28,8 @@
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.security.legacykeystore.ILegacyKeystore;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -77,7 +80,8 @@
@Test
public void testKeystoreMigrationAvoidedOnLegacyVendorPartition() {
when(WifiBlobStore.supplicantCanAccessBlobstore()).thenReturn(false);
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore();
+ assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
verifyNoMoreInteractions(mLegacyKeystore, mWifiBlobStore);
}
@@ -88,7 +92,8 @@
@Test
public void testKeystoreMigrationNoLegacyAliases() throws Exception {
when(mLegacyKeystore.list(anyString(), anyInt())).thenReturn(new String[0]);
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore();
+ assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
verify(mLegacyKeystore).list(anyString(), anyInt());
verifyNoMoreInteractions(mLegacyKeystore, mWifiBlobStore);
}
@@ -104,7 +109,8 @@
when(mLegacyKeystore.list(anyString(), anyInt())).thenReturn(legacyAliases);
when(mWifiBlobStore.list(anyString())).thenReturn(blobstoreAliases);
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore();
+ assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE,
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
verify(mWifiBlobStore, times(legacyAliases.length)).put(anyString(), any(byte[].class));
}
@@ -122,9 +128,35 @@
when(mWifiBlobStore.list(anyString())).thenReturn(blobstoreAliases);
// Expect that only the unique legacy alias is migrated to the blobstore
- WifiMigration.migrateLegacyKeystoreToWifiBlobstore();
+ assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE,
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
verify(mWifiBlobStore).list(anyString());
verify(mWifiBlobStore).put(eq(uniqueLegacyAlias), any(byte[].class));
verifyNoMoreInteractions(mWifiBlobStore);
}
+
+ /**
+ * Verify that the Keystore migration is skipped if Legacy Keystore is deprecated,
+ * since the migration is not needed.
+ */
+ @Test
+ public void testKeystoreMigrationAvoidedIfLegacyKsDeprecated() throws Exception {
+ // Legacy Keystore will throw a ServiceSpecificException with
+ // code ERROR_SYSTEM_ERROR if a method is deprecated
+ when(mLegacyKeystore.list(anyString(), anyInt())).thenThrow(
+ new ServiceSpecificException(ILegacyKeystore.ERROR_SYSTEM_ERROR));
+ assertEquals(WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED,
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+ }
+
+ /**
+ * Verify that the Keystore migration method returns a failure code when an
+ * unexpected exception is encountered.
+ */
+ @Test
+ public void testKeystoreMigrationFailsIfExceptionEncountered() throws Exception {
+ when(mLegacyKeystore.list(anyString(), anyInt())).thenThrow(new RemoteException());
+ assertEquals(WifiMigration.KEYSTORE_MIGRATION_FAILURE_ENCOUNTERED_EXCEPTION,
+ WifiMigration.migrateLegacyKeystoreToWifiBlobstore());
+ }
}